259 lines
9.3 KiB
TypeScript
259 lines
9.3 KiB
TypeScript
import { useEffect, useReducer } from 'react';
|
|
import { useForm, Controller, FormProvider } from 'react-hook-form';
|
|
import { initialState, reducer } from './reducer';
|
|
import { ProfileFormProps } from './ProfileFormProps.interface';
|
|
import { FormMode } from '../../enums/formMode';
|
|
import httpClient from '../../httpClient/httpClient';
|
|
import { AxiosError, AxiosInstance, AxiosResponse } from 'axios';
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
import { faSave, faXmark } from '@fortawesome/free-solid-svg-icons';
|
|
import { ScreenSize } from '../../enums/screenSize';
|
|
import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
|
|
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
|
import { Skill } from '../skills/Skill.interface';
|
|
import { useSkills } from '../../hooks/skills/UseSkills';
|
|
import MultiSelectDropdown from '../multiSelectDropdown/MultiSelectDropdown';
|
|
|
|
const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileFormProps) => {
|
|
const [state, dispatch] = useReducer(reducer, initialState);
|
|
const appContext = useAppContext();
|
|
const { skills } = useSkills();
|
|
const projectSkills: Skill[] = []
|
|
const defaultValues = {
|
|
name: '',
|
|
headline: '',
|
|
summary: '',
|
|
userId: '',
|
|
skills: projectSkills,
|
|
statusId: 1
|
|
}
|
|
const methods = useForm({
|
|
defaultValues: defaultValues
|
|
});
|
|
// const watchRepoName = methods.watch(['repoName'])
|
|
const { screenSize } = useBreakpoints();
|
|
|
|
const onSetSelectedSkills = (selectedSkill: Skill) => {
|
|
const selectedSkillExists = state.selectedSkills.find((skill) => skill.id === selectedSkill.id)
|
|
let newSelectedSkills: Skill[];
|
|
|
|
if (selectedSkillExists) {
|
|
newSelectedSkills = state.selectedSkills.filter((skill) => skill.id !== selectedSkillExists.id)
|
|
} else {
|
|
newSelectedSkills = [...state.selectedSkills, selectedSkill]
|
|
}
|
|
|
|
dispatch({ type: 'SET_SELECTED_SKILLS', payload: newSelectedSkills })
|
|
methods.setValue('skills', newSelectedSkills)
|
|
}
|
|
|
|
const onCancel = () => {
|
|
methods.reset(defaultValues);
|
|
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
|
onOpenClose(FormMode.CANCEL);
|
|
};
|
|
|
|
const onSubmit = async (data: any) => {
|
|
try {
|
|
dispatch({ type: 'SET_IS_LOADING', payload: true });
|
|
console.log(data)
|
|
if (!profileId) {
|
|
const newData = {
|
|
...data,
|
|
createdBy: appContext.state.userProfile.userPrincipalName,
|
|
userId: appContext.state.userProfile.userPrincipalName
|
|
}
|
|
console.log(newData)
|
|
await httpClient.post(`api/profiles`, newData);
|
|
} else {
|
|
const newData = {
|
|
...data,
|
|
updatedBy: appContext.state.userProfile.userPrincipalName
|
|
}
|
|
console.log(newData)
|
|
await httpClient.put(`api/profiles/${profileId}`, newData);
|
|
}
|
|
|
|
methods.reset(defaultValues);
|
|
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
|
onOpenClose(FormMode.CANCEL);
|
|
} catch (error) {
|
|
const axiosError = error as AxiosError;
|
|
console.log(axiosError)
|
|
dispatch({ type: 'SET_ERROR', payload: axiosError.message });
|
|
} finally {
|
|
dispatch({ type: 'SET_IS_LOADING', payload: false });
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (mode === FormMode.VIEW) {
|
|
dispatch({ type: 'SET_IS_DISABLED', payload: true });
|
|
}
|
|
}, [mode]);
|
|
|
|
useEffect(() => {
|
|
const getProfile = async () => {
|
|
try {
|
|
dispatch({ type: 'SET_IS_LOADING', payload: true });
|
|
|
|
const response: AxiosResponse = await httpClient.get(
|
|
`api/profiles/${profileId}`
|
|
);
|
|
const profile = response.data;
|
|
|
|
if (profile.skills) {
|
|
dispatch({ type: 'SET_SELECTED_SKILLS', payload: profile.skills })
|
|
}
|
|
|
|
methods.reset(profile);
|
|
} catch (error) {
|
|
const axiosError = error as AxiosError;
|
|
console.log(axiosError)
|
|
dispatch({ type: 'SET_ERROR', payload: axiosError.message });
|
|
} finally {
|
|
dispatch({ type: 'SET_IS_LOADING', payload: false });
|
|
}
|
|
};
|
|
|
|
if (profileId && isDrawerOpen) {
|
|
getProfile();
|
|
}
|
|
}, [profileId]);
|
|
|
|
useEffect(() => {
|
|
if (skills) {
|
|
dispatch({ type: 'SET_SKILL_OPTIONS', payload: skills })
|
|
}
|
|
}, [skills])
|
|
|
|
return (
|
|
<div className='drawer drawer-end'>
|
|
<input type='checkbox' className='drawer-toggle' onChange={() => {}} checked={isDrawerOpen} />
|
|
<div className='drawer-side'>
|
|
<label
|
|
htmlFor='my-drawer-1'
|
|
aria-label='close-sidebar'
|
|
className='drawer-overlay'
|
|
></label>
|
|
<div className={`menu bg-base-100 text-base-content min-h-full p-4 ${screenSize === ScreenSize.SM ? 'w-full' : screenSize === ScreenSize.MD ? 'w-[66%]' : 'w-[33%]'}`}>
|
|
<FormProvider {...methods}>
|
|
<form className='prose max-w-none' onSubmit={methods.handleSubmit(onSubmit)} style={{ paddingBottom: '50px' }}>
|
|
<div className='grid grid-cols-12 gap-3'>
|
|
<div className="col-span-10">
|
|
<h2 className="mt-0 mb-0 self-center">
|
|
{`${mode.toString().toLowerCase().charAt(0).toUpperCase() + mode.toString().slice(1).toLowerCase()} Profile`}
|
|
</h2>
|
|
</div>
|
|
<div className="col-span-2 justify-self-end self-center">
|
|
<button className="btn btn-ghost" onClick={onCancel}>
|
|
<FontAwesomeIcon icon={faXmark} />
|
|
</button>
|
|
</div>
|
|
<div className='col-span-3 self-center'>
|
|
<span>Name *</span>
|
|
</div>
|
|
<div className='col-span-9'>
|
|
<Controller
|
|
name="name"
|
|
control={methods.control}
|
|
rules={{ required: 'A profile title is required' }}
|
|
render={({ field: { onChange, value } }) => (
|
|
<input
|
|
type='text'
|
|
className='input w-full'
|
|
disabled={state.isDisabled}
|
|
onChange={onChange}
|
|
value={value}
|
|
/>
|
|
)}
|
|
/>
|
|
</div>
|
|
<div className='col-span-3 self-center'>
|
|
<span>Headline</span>
|
|
</div>
|
|
<div className='col-span-9'>
|
|
<Controller
|
|
name='headline'
|
|
control={methods.control}
|
|
render={({ field: { onChange, value } }) => (
|
|
<input
|
|
type='text'
|
|
className='input w-full'
|
|
disabled={state.isDisabled}
|
|
onChange={onChange}
|
|
value={value}
|
|
/>
|
|
)}
|
|
/>
|
|
</div>
|
|
<div className='col-span-3 self-center'>
|
|
<span>Summary</span>
|
|
</div>
|
|
<div className='col-span-9'>
|
|
<Controller
|
|
name="summary"
|
|
control={methods.control}
|
|
render={({ field: { onChange, value } }) => (
|
|
<input
|
|
type='text'
|
|
className='input w-full'
|
|
disabled={state.isDisabled}
|
|
onChange={onChange}
|
|
value={value}
|
|
/>
|
|
)}
|
|
/>
|
|
</div>
|
|
<div className={`col-span-3 self-center after:content-['*'] after:ms-0.5`}>
|
|
<span>Skills</span>
|
|
</div>
|
|
<div className='col-span-9'>
|
|
<Controller
|
|
name="skills"
|
|
control={methods.control}
|
|
render={() => (
|
|
<MultiSelectDropdown
|
|
skills={state.skillOptions}
|
|
onChange={onSetSelectedSkills}
|
|
selectedSkills={state.selectedSkills}
|
|
/>
|
|
)}
|
|
/>
|
|
</div>
|
|
<div className='col-span-12 justify-self-end self-center'>
|
|
<button
|
|
className='btn'
|
|
disabled={
|
|
state.isDisabled && mode.toString() !== FormMode.VIEW
|
|
? state.isDisabled
|
|
: false
|
|
}
|
|
onClick={onCancel}
|
|
data-testid="profile-cancel-button"
|
|
>
|
|
<FontAwesomeIcon icon={faXmark} />
|
|
{mode.toString() !== FormMode.VIEW ? 'Cancel' : 'Close'}
|
|
</button>
|
|
{mode.toString() !== FormMode.VIEW && (
|
|
<button
|
|
className='btn btn-primary ml-2.5'
|
|
disabled={state.isDisabled}
|
|
type="submit"
|
|
data-testid="profile-save-button"
|
|
>
|
|
<FontAwesomeIcon icon={faSave} />
|
|
Save
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</FormProvider>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default ProfileForm; |