diff --git a/.forestadmin-schema.json b/.forestadmin-schema.json index 03fbe5e39..811f3712a 100644 --- a/.forestadmin-schema.json +++ b/.forestadmin-schema.json @@ -1,4 +1,192 @@ [ + { + "actions": [], + "fields": [ + { + "defaultValue": null, + "enums": null, + "field": "Image", + "integration": null, + "inverseOf": "Experiences", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "Image.uid", + "relationship": "BelongsTo", + "type": "String", + "validations": [] + }, + { + "defaultValue": null, + "enums": null, + "field": "Member", + "integration": null, + "inverseOf": "Experiences", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "Member.uid", + "relationship": "BelongsTo", + "type": "String", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + }, + { + "defaultValue": null, + "enums": null, + "field": "companyName", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "String", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + }, + { + "defaultValue": false, + "enums": null, + "field": "currentTeam", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "Boolean", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + }, + { + "defaultValue": null, + "enums": null, + "field": "description", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "String", + "validations": [] + }, + { + "defaultValue": null, + "enums": null, + "field": "endDate", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "Date", + "validations": [] + }, + { + "defaultValue": null, + "enums": null, + "field": "id", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "Number", + "validations": [] + }, + { + "defaultValue": null, + "enums": null, + "field": "startDate", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "Date", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + }, + { + "defaultValue": null, + "enums": null, + "field": "title", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "String", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + }, + { + "defaultValue": null, + "enums": null, + "field": "uid", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "String", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + } + ], + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "name": "Experience", + "onlyForRelationships": false, + "paginationType": "page", + "segments": [] + }, { "actions": [], "fields": [ @@ -251,6 +439,23 @@ { "actions": [], "fields": [ + { + "defaultValue": null, + "enums": null, + "field": "Experiences", + "integration": null, + "inverseOf": "Image", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": false, + "isVirtual": false, + "reference": "Experience.uid", + "relationship": "HasMany", + "type": ["String"], + "validations": [] + }, { "defaultValue": null, "enums": null, @@ -836,6 +1041,122 @@ "paginationType": "page", "segments": [] }, + { + "actions": [], + "fields": [ + { + "defaultValue": null, + "enums": null, + "field": "createdAt", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "Date", + "validations": [] + }, + { + "defaultValue": null, + "enums": null, + "field": "email", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "String", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + }, + { + "defaultValue": null, + "enums": null, + "field": "id", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "Number", + "validations": [] + }, + { + "defaultValue": null, + "enums": null, + "field": "introduction", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "String", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + }, + { + "defaultValue": null, + "enums": null, + "field": "uid", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "String", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + }, + { + "defaultValue": null, + "enums": null, + "field": "updatedAt", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "Date", + "validations": [] + } + ], + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "name": "JoinRequest", + "onlyForRelationships": false, + "paginationType": "page", + "segments": [] + }, { "actions": [], "fields": [ @@ -1119,6 +1440,23 @@ } ], "fields": [ + { + "defaultValue": null, + "enums": null, + "field": "Experiences", + "integration": null, + "inverseOf": "Member", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": false, + "isVirtual": false, + "reference": "Experience.uid", + "relationship": "HasMany", + "type": ["String"], + "validations": [] + }, { "defaultValue": null, "enums": null, @@ -3326,5 +3664,155 @@ "onlyForRelationships": false, "paginationType": "page", "segments": [] + }, + { + "actions": [], + "fields": [ + { + "defaultValue": 0, + "enums": null, + "field": "applied_steps_count", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "Number", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + }, + { + "defaultValue": null, + "enums": null, + "field": "checksum", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "String", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + }, + { + "defaultValue": null, + "enums": null, + "field": "finished_at", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "Date", + "validations": [] + }, + { + "defaultValue": null, + "enums": null, + "field": "id", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "String", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + }, + { + "defaultValue": null, + "enums": null, + "field": "logs", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "String", + "validations": [] + }, + { + "defaultValue": null, + "enums": null, + "field": "migration_name", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "String", + "validations": [ + {"type": "is present", "message": "Failed validation rule: 'Present'"} + ] + }, + { + "defaultValue": null, + "enums": null, + "field": "rolled_back_at", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "Date", + "validations": [] + }, + { + "defaultValue": null, + "enums": null, + "field": "started_at", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "type": "Date", + "validations": [] + } + ], + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "name": "_prisma_migrations", + "onlyForRelationships": false, + "paginationType": "page", + "segments": [] } ] \ No newline at end of file diff --git a/apps/web-api/prisma/migrations/20231103093835_member_experience_end_date_optional/migration.sql b/apps/web-api/prisma/migrations/20231103093835_member_experience_end_date_optional/migration.sql new file mode 100644 index 000000000..95e720332 --- /dev/null +++ b/apps/web-api/prisma/migrations/20231103093835_member_experience_end_date_optional/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Experience" ALTER COLUMN "endDate" DROP NOT NULL; diff --git a/apps/web-api/prisma/schema.prisma b/apps/web-api/prisma/schema.prisma index dd7be0915..9b383bafb 100644 --- a/apps/web-api/prisma/schema.prisma +++ b/apps/web-api/prisma/schema.prisma @@ -241,7 +241,7 @@ model Experience { title String currentTeam Boolean @default(false) startDate DateTime - endDate DateTime + endDate DateTime? description String? memberUid String member Member? @relation(fields: [memberUid], references: [uid]) diff --git a/apps/web-api/src/participants-request/participants-request.service.ts b/apps/web-api/src/participants-request/participants-request.service.ts index e4b45b56e..4f935680b 100644 --- a/apps/web-api/src/participants-request/participants-request.service.ts +++ b/apps/web-api/src/participants-request/participants-request.service.ts @@ -309,7 +309,8 @@ export class ParticipantsRequestService { dataToSave['moreDetails'] = dataToProcess.moreDetails; dataToSave['plnStartDate'] = dataToProcess.plnStartDate; dataToSave['openToWork'] = dataToProcess.openToWork; - dataToSave['experience'] = dataToProcess.experience; + //dataToSave['experience'] = dataToProcess.experience; + // Team member roles relational mapping dataToSave['teamMemberRoles'] = { createMany: { @@ -321,14 +322,18 @@ export class ParticipantsRequestService { teamUid: t.teamUid, }; }), - }, - }; - dataToSave['experience'] = { - createMany: { - data: dataToProcess.experience }, }; + // Save Experience if available + if(dataToProcess.experience && Array.isArray(dataToProcess.experience) && dataToProcess.experience.length > 0) { + dataToSave['experience'] = { + createMany: { + data: dataToProcess.experience + }, + }; + } + // Skills relation mapping dataToSave['skills'] = { connect: dataToProcess.skills.map((s) => { @@ -424,6 +429,7 @@ export class ParticipantsRequestService { skills: true, teamMemberRoles: true, memberRoles: true, + experience: true }, }); const dataToProcess = dataFromDB?.newData; @@ -639,25 +645,22 @@ export class ParticipantsRequestService { }), }); - let expToCreate: any = []; - let expIdsTodelete:any = []; - let expIdsToUpdate:any = []; - - let expIds = dataToSave.experience?.map(exp => { - if (!exp.uid) { - expToCreate.push(exp); - } - return exp.uid; - }); - - dataFromDB.experience?.map((exp:any)=> { + const expToCreate: any = [...dataToProcess.experience].filter(exp => !exp.uid) + const expIdsTodelete:any = []; + const expIdsToUpdate:any = []; + + + const expIds = [...dataToProcess.experience].filter(exp => exp.uid).map(v => v.uid); + + existingData.experience?.map((exp:any)=> { if(!expIds.includes(exp.uid)) { - expIdsTodelete.push(exp.uid); + expIdsTodelete.push(exp.uid); } else { - expIdsToUpdate.push(exp); + expIdsToUpdate.push(exp.uid); } }); + const experienceToDelete = expIdsTodelete.map((uid) => tx.experience.delete({ where: { @@ -666,7 +669,8 @@ export class ParticipantsRequestService { }) ); - const experienceToUpdate = expIdsToUpdate.map((exp) => + const expsToUpdate = dataToProcess.experience.filter(v => expIdsToUpdate.includes(v.uid)) + const experienceToUpdate = expsToUpdate.map((exp) => tx.experience.update({ where: { uid: exp.uid diff --git a/apps/web-app/components/members/member-enrollment/add-member-experience-form.tsx b/apps/web-app/components/members/member-enrollment/add-member-experience-form.tsx new file mode 100644 index 000000000..8a1e8a1c3 --- /dev/null +++ b/apps/web-app/components/members/member-enrollment/add-member-experience-form.tsx @@ -0,0 +1,212 @@ +import { InputField, SingleSelect, Switch } from "@protocol-labs-network/ui"; +import api from "apps/web-app/utils/api"; +import { useRef, useState } from "react"; + +function AddMemberExperienceForm(props) { + const currentCompaniesCount = props.currentCompaniesCount; + const onItemChange = props.onItemChange; + const exp = props.exp; + const expIndex = props.expIndex; + const errors = props?.errors.filter(err => err?.id === expIndex); + const onDeleteExperience = props.onDeleteExperience; + const expandedId = props.expandedId; + const onToggleExpansion = props.onToggleExpansion; + const setLoaderStatus = props.setLoaderStatus + const uploadRef = useRef(null); + const descriptionRef = useRef(null); + const [isLogoHovered, setLogoHoverStatus] = useState(false); + + const getYears = () => { + const currentYear = new Date().getFullYear(); + const start = currentYear - 50; + const years = []; + for (let year = start; year <= currentYear; year++) { + years.push({ label: `${year}`, value: `${year}` }); + } + + return years; + } + const yearValues = getYears(); + const monthNames = [ + 'January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December' + ]; + const startMonthIndex = monthNames.indexOf(new Date(exp.startDate).toLocaleDateString(undefined, { month: 'long' })) + const endMonthIndex = monthNames.indexOf(new Date(exp.endDate).toLocaleDateString(undefined, { month: 'long' })) + const selectedStartYear = {label: `${new Date(exp.startDate).getFullYear()}`, value: `${new Date(exp.startDate).getFullYear()}`} + const selectedEndyear = {label: `${new Date(exp.endDate).getFullYear()}`, value: `${new Date(exp.endDate).getFullYear()}`} + + const getMonths = () => { + return [...monthNames].map(m => { + return { label: m, value: m } + }) + + } + + const onMonthChange = (field, value ) => { + const monthIndex = monthNames.indexOf(value); + const year = exp[field].getFullYear(); + const newDate = new Date(year, monthIndex); + onItemChange(expIndex, field, newDate) + } + + const onYearChange = (field, value) => { + const month = exp[field].getMonth(); + const newDate = new Date(parseInt(value, 10), month); + onItemChange(expIndex, field, newDate); + } + + function bytesToSize(bytes: number) { + return parseFloat((bytes / 1024 ** 2).toFixed(1)); + } + + const onHandleImageUpload = async (e) => { + setLoaderStatus(true) + const file = e.target.files?.[0]; + const isValidFormat = ['image/jpeg', 'image/png'].includes(file.type); + const sizeInMB = bytesToSize(file.size); + /* if(!isValidFormat) { + + } + if(sizeInMB > 4) { + } */ + + try { + const formData = new FormData(); + formData.append('file', file); + const config = { + headers: { + 'content-type': 'multipart/form-data', + }, + }; + + console.log("calling api") + const imageResponse = await api.post(`/v1/images`, formData, config); + const result = imageResponse.data.image; + onItemChange(expIndex, 'logoUid', result.uid); + onItemChange(expIndex, 'logoUrl', result.url); + console.log(result); + setLoaderStatus(false) + } catch (error) { + console.log(error) + setLoaderStatus(false) + } + + setLoaderStatus(false) + + } + + const onImageUpload = () => { + if(uploadRef?.current) { + console.log('in current') + uploadRef?.current?.click(); + } + } + + const onImageDelete = () => { + onItemChange(expIndex, 'logoUid', 0); + onItemChange(expIndex, 'logoUrl', ""); + } + + return <> +
+
+ + {/******************************** HEAD ***********************************/} +
0 ? 'border-[1px] border-solid border-[#ED6E68]': ''} h-[32px] flex items-center justify-between px-[8px]`}> +
+ {expIndex === expandedId && onToggleExpansion(expIndex)} src="/assets/images/icons/collapse-blue.svg" />} + {expIndex !== expandedId && onToggleExpansion(expIndex)} src="/assets/images/icons/expand-blue.svg" />} + onDeleteExperience(expIndex)} className="cursor-pointer" src="/assets/images/icons/delete-icon.svg" /> +
+ {exp.companyName.trim() === '' &&

{`Company ${expIndex + 1}`}

} + {exp.companyName.trim() !== '' &&

{`${exp.companyName.trim()}`}

} +
+ onItemChange(expIndex, 'currentTeam', val)} key={`${expIndex}-switch`} /> + +
+
+ + {expIndex === expandedId &&
+ {/*********************************** ERRORS ***************************************/} +
    {errors.map((err, errIndex) =>
  • {err.error}
  • )}
+ {/******************************** LOGO & COMPANY NAME ***********************************/} +
+ {!exp.logoUrl &&
+ +

Add Logo

+ +
} + {exp.logoUrl &&
setLogoHoverStatus(false)} onMouseOver={() => setLogoHoverStatus(true)} onClick={onImageUpload} className="flex relative rounded-[8px] cursor-pointer border-[#CBD5E1] bg-[#F1F5F9] border-solid border-[3px] h-[100px] w-[100px] flex-col items-center justify-center"> + + {isLogoHovered &&
+ + +
} +
} +
+ + onItemChange(expIndex, 'companyName', e.target.value)} /> +
+
+
+ +

Please upload a squared image in PNG or JPEG format only

+ +
+ + {/******************************** TITLE ***********************************/} +
+ + onItemChange(expIndex, 'title', e.target.value)} /> +
+ + + + + {/******************************** DATES ***********************************/} +
+
+

From*

+
+
onMonthChange('startDate', option.value)} initialOption={getMonths()[startMonthIndex]} placeholder="Select Month" options={getMonths()} />
+
onYearChange('startDate', option.value)} initialOption={selectedStartYear} placeholder="Select Year" options={[...yearValues]} />
+
+ +
+
+ {exp?.endDate &&

To*

} + {!exp?.endDate &&

To

} + {exp?.endDate &&
+
onMonthChange('endDate', option.value)} initialOption={getMonths()[endMonthIndex]} placeholder="Select Month" options={getMonths()} />
+
onYearChange('endDate', option.value)} initialOption={selectedEndyear} placeholder="Select Year" options={[...yearValues]} />
+
} + {!exp?.endDate &&
+
e.preventDefault()} className="w-full border-[1px] rounded-[8px] px-[8px] border-solid border-[#CBD5E1] h-[40px] text-[13px]" placeholder="Month" disabled/>
+
e.preventDefault()} className="w-full border-[1px] rounded-[8px] px-[8px] border-solid border-[#CBD5E1] h-[40px] text-[13px]" placeholder="Year" disabled/>
+
} +
+
+ + {/******************************** DESCRIPTION ***********************************/} +
+ +