adding skills to experiences, profiles, and projects
Some checks failed
Main / changes (push) Successful in 37s
Main / deploy (push) Has been cancelled
Main / build-and-test (push) Has been cancelled

This commit is contained in:
2026-07-20 19:28:37 -05:00
parent 9d9cdbaebc
commit e5219761c2
40 changed files with 15075 additions and 162 deletions

View File

@@ -9,11 +9,15 @@ import { AxiosError, AxiosResponse } from "axios";
import { ScreenSize } from "../../enums/screenSize";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faSave, faXmark } from "@fortawesome/free-solid-svg-icons";
import { useAppContext } from "../../hooks/appContext/UseAppContext";
const SkillCategoryForm = ({ isDrawerOpen, mode, onOpenClose, categoryId }: SkillCategoryFormProps) => {
const [state, dispatch] = useReducer(reducer, initialState);
const appContext = useAppContext();
const defaultValues = {
name: ''
name: '',
createdBy: '',
updatedBy: ''
}
const methods = useForm({
defaultValues: defaultValues
@@ -26,14 +30,25 @@ const SkillCategoryForm = ({ isDrawerOpen, mode, onOpenClose, categoryId }: Skil
onOpenClose(FormMode.CANCEL)
}
const onSubmit = async (data: unknown) => {
const onSubmit = async (data: any) => {
try {
dispatch({ type: 'SET_IS_LOADING', payload: true })
if (!categoryId) {
await httpClient.post(`api/skill-categories`, data);
const newData = {
...data,
createdBy: appContext.state.userProfile.userPrincipalName,
updatedBy: appContext.state.userProfile.userPrincipalName
}
await httpClient.post(`api/skill-categories`, newData);
} else {
await httpClient.put(`api/skill-categories`)
const newData = {
...data,
updatedBy: appContext.state.userProfile.userPrincipalName
}
await httpClient.put(`api/skill-categories`, newData)
}
methods.reset(defaultValues);

View File

@@ -9,14 +9,18 @@ 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';
const SkillForm = ({ isDrawerOpen, mode, onOpenClose, skillId }: SkillFormProps) => {
const [state, dispatch] = useReducer(reducer, initialState);
const appContext = useAppContext();
const defaultValues = {
name: '',
categoryId: '',
levelId: '',
rankId: ''
rankId: '',
createdBy: '',
updatedBy: ''
}
const methods = useForm({
defaultValues: defaultValues
@@ -29,14 +33,25 @@ const SkillForm = ({ isDrawerOpen, mode, onOpenClose, skillId }: SkillFormProps)
onOpenClose(FormMode.CANCEL);
};
const onSubmit = async (data: unknown) => {
const onSubmit = async (data: any) => {
try {
dispatch({ type: 'SET_IS_LOADING', payload: true });
console.log(data)
if (!skillId) {
await httpClient.post(`api/skills`, data);
const newData = {
...data,
createdBy: appContext.state.userProfile.userPrincipalName,
updatedBy: appContext.state.userProfile.userPrincipalName
}
await httpClient.post(`api/skills`, newData);
} else {
await httpClient.put(`api/skills/skill/${skillId}`, data);
const newData = {
...data,
updatedBy: appContext.state.userProfile.userPrincipalName
}
await httpClient.put(`api/skills/skill/${skillId}`, newData);
}
methods.reset(defaultValues);

View File

@@ -12,14 +12,17 @@ import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
import { Profile } from '../profiles/Profile.interface';
import { useProfiles } from '../../hooks/profiles/UseProfiles';
import { useAppContext } from '../../hooks/appContext/UseAppContext';
import { Listbox, ListboxButton, ListboxOption, ListboxOptions } from '@headlessui/react';
import { useSkills } from '../../hooks/skills/UseSkills';
import MultiSelectDropdown from '../multiSelectDropdown/MultiSelectDropdown';
import { Skill } from '../skills/Skill.interface';
import { Experience } from '../experiences/Experience.interface';
const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: ExperienceFormProps) => {
const [state, dispatch] = useReducer(reducer, initialState);
const appContext = useAppContext();
const { profiles } = useProfiles();
const { skills } = useSkills();
const experienceSkills: Skill[] = []
const defaultValues = {
profileId: '',
companyName: '',
@@ -27,7 +30,7 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
title: '',
startDate: '',
endDate: '',
skills: [],
skills: experienceSkills,
summary: '',
statusId: 1,
createdBy: '',
@@ -36,9 +39,23 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
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 });
@@ -91,6 +108,10 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
`api/experiences/${experienceId}`
);
const experience = response.data;
if (experience.skills) {
dispatch({ type: 'SET_SELECTED_SKILLS', payload: experience.skills })
}
methods.reset(experience);
} catch (error) {
@@ -127,7 +148,9 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
}, [profiles]);
useEffect(() => {
dispatch({ type: 'SET_SKILL_OPTIONS', payload: skills })
if (skills) {
dispatch({ type: 'SET_SKILL_OPTIONS', payload: skills })
}
}, [skills])
return (
@@ -296,23 +319,12 @@ const ExperienceForm = ({ isDrawerOpen, mode, onOpenClose, experienceId }: Exper
<Controller
name="skills"
control={methods.control}
render={({ field: { onChange, value } }) => (
// <input
// type='text'
// className='input w-full'
// disabled={state.isDisabled}
// onChange={onChange}
// value={value}
// />
<Listbox value={value} onChange={onChange}>
<ListboxOptions anchor='bottom'>
{state.skillOptions?.map((skill) => (
<ListboxOption key={skill.id} value={skill.id}>
{skill.name}
</ListboxOption>
))}
</ListboxOptions>
</Listbox>
render={() => (
<MultiSelectDropdown
skills={state.skillOptions}
onChange={onSetSelectedSkills}
selectedSkills={state.selectedSkills}
/>
)}
/>
</div>

View File

@@ -6,5 +6,6 @@ export interface ExperienceFormState {
isDisabled: boolean;
isLoading: boolean;
profileOptions: Profile[];
skillOptions: Skill[] | undefined;
selectedSkills: Skill[];
skillOptions: Skill[];
}

View File

@@ -7,13 +7,15 @@ type Action =
| { type: 'SET_IS_DISABLED'; payload: boolean }
| { type: 'SET_IS_LOADING'; payload: boolean }
| { type: 'SET_PROFILE_OPTIONS'; payload: Profile[] }
| { type: 'SET_SKILL_OPTIONS'; payload: Skill[] | undefined };
| { type: 'SET_SELECTED_SKILLS'; payload: Skill[] }
| { type: 'SET_SKILL_OPTIONS'; payload: Skill[] };
export const initialState: ExperienceFormState = {
error: undefined,
isDisabled: false,
isLoading: true,
profileOptions: [],
selectedSkills: [],
skillOptions: []
};
@@ -46,6 +48,12 @@ export const reducer = (
profileOptions: action.payload
}
}
case 'SET_SELECTED_SKILLS': {
return {
...state,
selectedSkills: action.payload
}
}
case 'SET_SKILL_OPTIONS': {
return {
...state,

View File

@@ -12,7 +12,7 @@ export interface Experience {
startDate: Date;
endDate?: Date;
summary?: string;
skills: Skill[];
skills?: Skill[];
profile: Profile;
status: Status;
}

View File

@@ -17,6 +17,7 @@ import { useUserRole } from '../../hooks/userRole/UseUserRole';
import Alert from '../../alert/Alert';
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
import { Profile } from '../profiles/Profile.interface';
import { Skill } from '../skills/Skill.interface';
interface ActionsProps {
id: string;
@@ -166,6 +167,17 @@ const Experiences = () => {
accessorKey: 'summary',
header: 'Summary'
},
{
id: 'skills',
accessorKey: 'skills',
header: 'Skills',
cell: (info: CellContext<Experience, unknown>) => {
const skills = info.getValue() as Skill[];
const skillsString: string = skills.map((skill) => skill.name).join(', ')
return skillsString
}
},
{
id: 'status',
accessorKey: 'status',

View File

@@ -1,32 +1,33 @@
import { useEffect, useRef, useState } from "react";
import { MultiSelectDropdownProps } from "./MultiSelectDropdownProps";
import { Skill } from "../skills/Skill.interface";
const MultiSelectDropdown = ({ options }: MultiSelectDropdownProps) => {
const MultiSelectDropdown = ({ onChange, skills, selectedSkills }: MultiSelectDropdownProps) => {
const [isOpen, setIsOpen] = useState(false);
const [selectedValues, setSelectedValues] = useState([])
// const [selectedValues, setSelectedValues] = useState([])
const dropdownRef = useRef(null)
const handleToggleOption = (value: any) => {
let updated;
// let updated;
if (selectedValues.includes(value)) {
updated = selectedValues.filter((item) => item !== value);
} else {
updated = [...selectedValues, value];
}
// if (selectedValues.includes(value)) {
// updated = selectedValues.filter((item) => item !== value);
// } else {
// updated = [...selectedValues, value];
// }
setSelectedValues(updated);
if (onChange) onChange(updated)
// setSelectedValues(updated);
// if (onChange) onChange(updated)
}
const handleRemoveBadge = (event, value) => {
event.stopPropagation();
// event.stopPropagation();
const updated = selectedValues.filter((item) => item !== value);
// const updated = selectedValues.filter((item) => item !== value);
setSelectedValues(updated)
// setSelectedValues(updated)
if (onChange) onchange(updated)
// if (onChange) onchange(updated)
}
useEffect(() => {
@@ -50,21 +51,15 @@ const MultiSelectDropdown = ({ options }: MultiSelectDropdownProps) => {
className="select select-bordered w-full h-auto min-h-12 flex flex-wrap items-center gap-1 p-2 bg-base-100 text-left cursor-pointer"
onClick={() => setIsOpen(!isOpen)}
>
{selectedValues.length === 0 ? (
{selectedSkills.length === 0 ? (
<span className="text-base-content/50"></span>
) : (
<div className="flex flex-wrap gap-1">
{selectedValues.map((val) => {
const option = options.find((o: any) => o.value === val);
{selectedSkills.map((selectedSkill: Skill) => {
const option = skills.find((skill: Skill) => skill.id === selectedSkill.id);
return (
<div key={val} className="badge badge-primary gap-1 py-3 px-2">
{option?.label || val}
<button
onClick={(event) => handleRemoveBadge(event, val)}
className="btn btn-ghost btn-xs p-0 min-h-0 h-auto text-primary-content hover:bg-transparent"
>
</button>
<div key={selectedSkill.id} className="badge badge-primary gap-1 py-3 px-2">
{option?.name || selectedSkill.name}
</div>
);
})}
@@ -75,16 +70,16 @@ const MultiSelectDropdown = ({ options }: MultiSelectDropdownProps) => {
tabIndex={0}
className="dropdown-content menu p-2 shadow-lg bg-base-100 rounded-box w-full max-h-60 overflow-y-auto z-[1] border border-base-200"
>
{options.map((option) => (
<li key={option.value} className="p-0">
{skills.map((skill) => (
<li key={skill.id} className="p-0">
<label className="label cursor-pointer justify-start gap-3 px-4 py-2 hover:bg-base-200 rounded-lg w-full">
<input
type="checkbox"
className="checkbox checkbox-primary checkbox-sm"
checked={selectedValues.includes(option.value)}
onChange={() => handleToggleOption(option.value)}
checked={selectedSkills.includes(skill)}
onChange={() => onChange(skill)}
/>
<span className="label-text text-base-content">{option.label}</span>
<span className="label-text text-base-content">{skill.name}</span>
</label>
</li>
))}

View File

@@ -1,3 +1,7 @@
import { Skill } from "../skills/Skill.interface";
export interface MultiSelectDropdownProps {
options: { label: string; value: string }[];
onChange: (selectedSkill: Skill) => void;
skills: Skill[];
selectedSkills: Skill[];
}

View File

@@ -10,15 +10,21 @@ 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({
@@ -27,6 +33,20 @@ const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileForm
// 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 });
@@ -80,9 +100,13 @@ const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileForm
const response: AxiosResponse = await httpClient.get(
`api/profiles/${profileId}`
);
const entry = response.data;
const profile = response.data;
methods.reset(entry);
if (profile.skills) {
dispatch({ type: 'SET_SELECTED_SKILLS', payload: profile.skills })
}
methods.reset(profile);
} catch (error) {
const axiosError = error as AxiosError;
console.log(axiosError)
@@ -97,6 +121,12 @@ const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileForm
}
}, [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} />
@@ -175,6 +205,22 @@ const ProfileForm = ({ isDrawerOpen, mode, onOpenClose, profileId }: ProfileForm
)}
/>
</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'

View File

@@ -1,5 +1,9 @@
import { Skill } from "../skills/Skill.interface";
export interface ProfileFormState {
error: string | undefined;
isDisabled: boolean;
isLoading: boolean;
selectedSkills: Skill[];
skillOptions: Skill[];
}

View File

@@ -1,15 +1,20 @@
import { Profile } from "../profiles/Profile.interface";
import { Skill } from "../skills/Skill.interface";
import { ProfileFormState } from "./ProfileFormState.interface"
type Action =
| { type: 'SET_ERROR'; payload: string | undefined }
| { type: 'SET_IS_DISABLED'; payload: boolean }
| { type: 'SET_IS_LOADING'; payload: boolean };
| { type: 'SET_IS_LOADING'; payload: boolean }
| { type: 'SET_SELECTED_SKILLS'; payload: Skill[] }
| { type: 'SET_SKILL_OPTIONS'; payload: Skill[] };
export const initialState: ProfileFormState = {
error: undefined,
isDisabled: false,
isLoading: true
isLoading: true,
selectedSkills: [],
skillOptions: []
};
export const reducer = (
@@ -34,6 +39,18 @@ export const reducer = (
...state,
isLoading: action.payload
};
}
case 'SET_SELECTED_SKILLS': {
return {
...state,
selectedSkills: action.payload
}
}
case 'SET_SKILL_OPTIONS': {
return {
...state,
skillOptions: action.payload
}
}
default: {
return state;

View File

@@ -16,6 +16,7 @@ import { UserRole } from '../../enums/userRole';
import { useUserRole } from '../../hooks/userRole/UseUserRole';
import Alert from '../../alert/Alert';
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
import { Skill } from '../skills/Skill.interface';
interface ActionsProps {
id: string;
@@ -144,6 +145,17 @@ const Profiles = () => {
accessorKey: 'summary',
header: 'Summary'
},
{
id: 'skills',
accessorKey: 'skills',
header: 'Skills',
cell: (info: CellContext<Profile, unknown>) => {
const skills = info.getValue() as Skill[];
const skillsString: string = skills.map((skill) => skill.name).join(', ')
return skillsString
}
},
{
id: 'status',
accessorKey: 'status',

View File

@@ -11,10 +11,15 @@ import { ScreenSize } from '../../enums/screenSize';
import { useBreakpoints } from '../../hooks/breakpoints/UseBreakpoints';
import { useProfiles } from '../../hooks/profiles/UseProfiles';
import { Profile } from '../profiles/Profile.interface';
import { Skill } from '../skills/Skill.interface';
import { useSkills } from '../../hooks/skills/UseSkills';
import MultiSelectDropdown from '../multiSelectDropdown/MultiSelectDropdown';
const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectFormProps) => {
const [state, dispatch] = useReducer(reducer, initialState);
const { profiles } = useProfiles()
const { profiles } = useProfiles();
const { skills } = useSkills();
const projectSkills: Skill[] = []
const defaultValues = {
profileId: '',
name: '',
@@ -23,6 +28,7 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
repoUrl: '',
siteUrl: '',
order: '',
skills: projectSkills,
statusId: 1
}
const methods = useForm({
@@ -31,6 +37,20 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
// 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 });
@@ -44,7 +64,7 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
if (!projectId) {
await httpClient.post(`api/projects`, data);
} else {
await httpClient.put(`api/projects/project/${projectId}`, data);
await httpClient.put(`api/projects/${projectId}`, data);
}
methods.reset(defaultValues);
@@ -77,11 +97,15 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
dispatch({ type: 'SET_IS_LOADING', payload: true });
const response: AxiosResponse = await httpClient.get(
`api/projects/project/${projectId}`
`api/projects/${projectId}`
);
const entry = response.data;
const project = response.data;
methods.reset(entry);
if (project.skills) {
dispatch({ type: 'SET_SELECTED_SKILLS', payload: project.skills })
}
methods.reset(project);
} catch (error) {
const axiosError = error as AxiosError;
console.log(axiosError)
@@ -107,13 +131,20 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
summary: '',
userId: '',
experiences: [],
skills: []
skills: [],
status: null
})
dispatch({ type: 'SET_PROFILE_OPTIONS', payload: newProfileOptions });
}
}, [profiles]);
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} />
@@ -272,6 +303,22 @@ const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectForm
)}
/>
</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'

View File

@@ -1,8 +1,11 @@
import { Profile } from "../profiles/Profile.interface";
import { Skill } from "../skills/Skill.interface";
export interface ProjectFormState {
error: string | undefined;
isDisabled: boolean;
isLoading: boolean;
profileOptions: Profile[];
selectedSkills: Skill[];
skillOptions: Skill[];
}

View File

@@ -1,17 +1,22 @@
import { Profile } from "../profiles/Profile.interface";
import { Skill } from "../skills/Skill.interface";
import { ProjectFormState } from "./ProjectFormState.interface"
type Action =
| { type: 'SET_ERROR'; payload: string | undefined }
| { type: 'SET_IS_DISABLED'; payload: boolean }
| { type: 'SET_IS_LOADING'; payload: boolean }
| { type: 'SET_PROFILE_OPTIONS'; payload: Profile[] };
| { type: 'SET_PROFILE_OPTIONS'; payload: Profile[] }
| { type: 'SET_SELECTED_SKILLS'; payload: Skill[] }
| { type: 'SET_SKILL_OPTIONS'; payload: Skill[] };
export const initialState: ProjectFormState = {
error: undefined,
isDisabled: false,
isLoading: true,
profileOptions: []
profileOptions: [],
selectedSkills: [],
skillOptions: []
};
export const reducer = (
@@ -43,6 +48,18 @@ export const reducer = (
profileOptions: action.payload
}
}
case 'SET_SELECTED_SKILLS': {
return {
...state,
selectedSkills: action.payload
}
}
case 'SET_SKILL_OPTIONS': {
return {
...state,
skillOptions: action.payload
}
}
default: {
return state;
}

View File

@@ -1,20 +1,4 @@
import { Project } from './Project.interface';
// import {
// Alert,
// Box,
// Button,
// Card,
// CardActions,
// CardContent,
// CardHeader,
// Container,
// Grid,
// Icon,
// IconName,
// Skeleton,
// Stack,
// Typography
// } from '@noahspan/noahspan-components';
import { FormMode } from '../../enums/formMode';
import { useEffect, useReducer } from 'react';
import { initialState, reducer } from './reducer';
@@ -32,6 +16,7 @@ import { UserRole } from '../../enums/userRole';
import { useUserRole } from '../../hooks/userRole/UseUserRole';
import Alert from '../../alert/Alert';
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
import { Skill } from '../skills/Skill.interface';
interface ActionsProps {
id: string;
@@ -169,6 +154,17 @@ const Projects = () => {
accessorKey: 'summary',
header: 'Summary'
},
{
id: 'skills',
accessorKey: 'skills',
header: 'Skills',
cell: (info: CellContext<Project, unknown>) => {
const skills = info.getValue() as Skill[];
const skillsString: string = skills.map((skill) => skill.name).join(', ')
return skillsString
}
},
{
id: 'status',
accessorKey: 'status',