diff --git a/.gitignore b/.gitignore index f59d863b..ef1e6bca 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ .env.development.local .env.test.local .env.production.local +a.json *.log* npm-debug.log* diff --git a/CHANGELOG.md b/CHANGELOG.md index 136753ee..d0f9c7eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ ## Neste versjon +## Versjon 2024.22.10 + +- ✨ **Gruppe**. HS kan nå opprette grupper. + ## Versjon 2024.15.10 - ✨ **Betalinger**. Man kan nå se hvem på deltagerlisten som har betalt for arrangementet. diff --git a/src/AppRoutes.tsx b/src/AppRoutes.tsx index 06979c86..b098706a 100644 --- a/src/AppRoutes.tsx +++ b/src/AppRoutes.tsx @@ -38,6 +38,7 @@ const BadgesCategoryLeaderboard = lazy(() => import('pages/Badges/category/Badge const Cheatsheet = lazy(() => import('pages/Cheatsheet')); const EventAdministration = lazy(() => import('pages/EventAdministration')); const EventRegistration = lazy(() => import('pages/EventRegistration')); +const NewGroupAdministration = lazy(() => import('pages/NewGroupAdministration')); const ForgotPassword = lazy(() => import('pages/ForgotPassword')); const Form = lazy(() => import('pages/Form')); const FormAdmin = lazy(() => import('pages/Form/FormAdmin')); @@ -154,10 +155,11 @@ const AppRoutes = () => { } />} path={URLS.shortLinks} /> } />} path={URLS.qrCodes} /> } />} path={URLS.admissions} /> - } />} path={URLS.bannerAdmin}> } /> + } />} path={URLS.newGroupAdmin} /> + } />} path={URLS.jobpostsAdmin}> } path=':jobPostId/' /> diff --git a/src/URLS.tsx b/src/URLS.tsx index ee58c6dc..f2c60ee4 100644 --- a/src/URLS.tsx +++ b/src/URLS.tsx @@ -57,6 +57,7 @@ const URLS = { qrCodes: '/qr-koder/', gallery: '/galleri/', userAdmin: '/admin/brukere/', + newGroupAdmin: '/admin/ny-gruppe/', strikeAdmin: '/admin/prikker/', eventAdmin: '/admin/arrangementer/', jobpostsAdmin: '/admin/karriere/', diff --git a/src/api/api.tsx b/src/api/api.tsx index 6743cc39..7fb0acbb 100644 --- a/src/api/api.tsx +++ b/src/api/api.tsx @@ -340,6 +340,7 @@ export default { getGroup: (slug: Group['slug']) => IFetch({ method: 'GET', url: `${GROUPS_ENDPOINT}/${slug}/` }), getGroupStatistics: (slug: Group['slug']) => IFetch({ method: 'GET', url: `${GROUPS_ENDPOINT}/${slug}/statistics/` }), updateGroup: (slug: Group['slug'], data: GroupMutate) => IFetch({ method: 'PUT', url: `${GROUPS_ENDPOINT}/${slug}/`, data }), + createGroup: (data: GroupMutate) => IFetch({ method: 'POST', url: `${GROUPS_ENDPOINT}/`, data }), // Group laws getGroupLaws: (groupSlug: Group['slug']) => IFetch>({ method: 'GET', url: `${GROUPS_ENDPOINT}/${groupSlug}/${GROUP_LAWS_ENDPOINT}/` }), diff --git a/src/hooks/Group.tsx b/src/hooks/Group.tsx index 9b200df5..44952da1 100644 --- a/src/hooks/Group.tsx +++ b/src/hooks/Group.tsx @@ -4,6 +4,7 @@ import { QueryKey, useInfiniteQuery, UseInfiniteQueryOptions, useMutation, UseMu import { Group, + GroupCreate, GroupFine, GroupFineBatchMutate, GroupFineCreate, @@ -224,3 +225,14 @@ export const useGroupForms = (groupSlug: string, enabled?: boolean) => export const useGroupStatistics = (groupSlug: string) => useQuery(GROUPS_QUERY_KEYS.statistics(groupSlug), () => API.getGroupStatistics(groupSlug)); + +export const useCreateGroup = (): UseMutationResult => { + const queryClient = useQueryClient(); + + return useMutation((group) => API.createGroup(group), { + onSuccess: (data) => { + queryClient.invalidateQueries(GROUPS_QUERY_KEYS.all); + queryClient.setQueryData(GROUPS_QUERY_KEYS.detail(data.slug), data); + }, + }); +}; diff --git a/src/pages/NewGroupAdministration/index.tsx b/src/pages/NewGroupAdministration/index.tsx new file mode 100644 index 00000000..d080ecfd --- /dev/null +++ b/src/pages/NewGroupAdministration/index.tsx @@ -0,0 +1,95 @@ +import { zodResolver } from '@hookform/resolvers/zod'; +import { useForm } from 'react-hook-form'; +import { toast } from 'sonner'; +import { z } from 'zod'; + +import { GroupCreate } from 'types'; +import { GroupType } from 'types/Enums'; + +import { useCreateGroup } from 'hooks/Group'; + +import FormInput from 'components/inputs/Input'; +import { FormSelect } from 'components/inputs/Select'; +import { Button } from 'components/ui/button'; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from 'components/ui/card'; +import { Form } from 'components/ui/form'; + +const schema = z.object({ + name: z.string({ message: 'Gruppenavn er påkrevd' }), + slug: z.string({ message: 'Gruppeslug er påkrevd' }), + type: z.nativeEnum(GroupType, { message: 'Gruppetype er påkrevd' }), +}); + +export default function NewGroupAdministration() { + const createGroup = useCreateGroup(); + + const form = useForm>({ + resolver: zodResolver(schema), + defaultValues: { name: '', slug: '', type: GroupType.BOARD }, + }); + + const onSubmit = (values: z.infer) => { + const data: GroupCreate = { + name: values.name, + slug: values.slug.toLowerCase(), + type: values.type, + }; + + createGroup.mutate(data, { + onSuccess: () => { + toast.success('Gruppen ble opprettet'); + form.reset(); + }, + onError: (e) => { + Object.keys(e.detail).forEach((key: string) => { + if (key in data) { + const errorKey = key as keyof GroupCreate; + const errorMessage = (e.detail as unknown as Record)[key]; + form.setError(errorKey, { message: errorMessage }); + } + }); + toast.error('Det er en eller flere feil i skjemaet'); + }, + }); + }; + + return ( +
+ + + Opprett ny gruppe + Velg gruppetype og opprett en ny gruppe. + + +
+ + + + + + + +
+
+
+ ); +} diff --git a/src/pages/Profile/components/ProfileAdmin.tsx b/src/pages/Profile/components/ProfileAdmin.tsx index 80c370f8..f9ca9fab 100644 --- a/src/pages/Profile/components/ProfileAdmin.tsx +++ b/src/pages/Profile/components/ProfileAdmin.tsx @@ -1,4 +1,4 @@ -import { Boxes, BriefcaseBusiness, Calendar, ChevronRightIcon, Grip, Info, LucideIcon, Newspaper, Users } from 'lucide-react'; +import { Boxes, BriefcaseBusiness, Calendar, ChevronRightIcon, Grip, Info, LucideIcon, Newspaper, Plus, Users } from 'lucide-react'; import { Link } from 'react-router-dom'; import URLS from 'URLS'; @@ -86,6 +86,13 @@ const Admin = () => { primary: 'Bannere', secondary: 'Opprett, endre og slett bannere', }, + { + apps: [PermissionApp.GROUP], + icon: Plus, + to: URLS.newGroupAdmin, + primary: 'Ny gruppe', + secondary: 'Legg til en ny gruppe', + }, ]; return ( diff --git a/src/types/Group.tsx b/src/types/Group.tsx index 16eae674..5c6729e8 100644 --- a/src/types/Group.tsx +++ b/src/types/Group.tsx @@ -49,6 +49,12 @@ export type GroupMutate = Partial