Skip to content

Commit a6d244f

Browse files
committed
i dont have time to write commit message. thanks. bye
1 parent 0b7ccdf commit a6d244f

File tree

11 files changed

+502
-146
lines changed

11 files changed

+502
-146
lines changed

apps/dashboard/src/app/(internal)/brukere/components/create-membership-modal.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { type ContextModalProps, modals } from "@mantine/modals"
33
import type { FC } from "react"
44
import { useCreateMembershipMutation } from "../mutations"
55
import { useMembershipWriteForm } from "./membership-form"
6+
import { Stack, Text } from "@mantine/core"
67

78
export const CreateMembershipModal: FC<ContextModalProps<{ user: User }>> = ({ context, id, innerProps: { user } }) => {
89
const close = () => context.closeModal(id)
@@ -16,7 +17,14 @@ export const CreateMembershipModal: FC<ContextModalProps<{ user: User }>> = ({ c
1617
close()
1718
},
1819
})
19-
return <FormComponent />
20+
return (
21+
<Stack gap="sm">
22+
<Text size="sm" c="dimmed">
23+
Rediger semesterverdien for å endre årstrinn.
24+
</Text>
25+
<FormComponent />
26+
</Stack>
27+
)
2028
}
2129

2230
export const useCreateMembershipModal =

apps/dashboard/src/app/(internal)/brukere/components/edit-membership-modal.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { type ContextModalProps, modals } from "@mantine/modals"
33
import type { FC } from "react"
44
import { useUpdateMembershipMutation } from "../mutations"
55
import { useMembershipWriteForm } from "./membership-form"
6+
import { Stack, Text } from "@mantine/core"
67

78
export const EditMembershipModal: FC<ContextModalProps<{ membership: Membership }>> = ({
89
context,
@@ -21,7 +22,14 @@ export const EditMembershipModal: FC<ContextModalProps<{ membership: Membership
2122
close()
2223
},
2324
})
24-
return <FormComponent />
25+
return (
26+
<Stack gap="sm">
27+
<Text size="sm" c="dimmed">
28+
Rediger semesterverdien for å endre årstrinn.
29+
</Text>
30+
<FormComponent />
31+
</Stack>
32+
)
2533
}
2634

2735
export const useEditMembershipModal =
Lines changed: 260 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { createDateTimeInput } from "@/components/forms/DateTimeInput"
21
import { useFormBuilder } from "@/components/forms/Form"
32
import { createSelectInput } from "@/components/forms/SelectInput"
43
import {
@@ -9,20 +8,100 @@ import {
98
getMembershipTypeName,
109
getSpecializationName,
1110
} from "@dotkomonline/types"
12-
import { getNextSemesterStart, getCurrentSemesterStart } from "@dotkomonline/utils"
13-
import { isBefore } from "date-fns"
11+
import {
12+
getCurrentSemesterStart,
13+
getNextSemesterStart,
14+
getStudyGrade,
15+
getCurrentUTC,
16+
getPreviousSemesterStart,
17+
isSpringSemester,
18+
} from "@dotkomonline/utils"
19+
import { isBefore, roundToNearestHours } from "date-fns"
1420
import type { z } from "zod"
15-
import { createNumberInput } from "@/components/forms/NumberInput"
16-
import { Code, Stack, Text } from "@mantine/core"
21+
import { ActionIcon, Button, Group, NumberInput, Stack } from "@mantine/core"
22+
import { Controller } from "react-hook-form"
23+
import { ErrorMessage } from "@hookform/error-message"
24+
import { DatePickerInput } from "@mantine/dates"
25+
import { IconArrowLeft, IconArrowRight, IconX } from "@tabler/icons-react"
26+
27+
const BACHELOR_SEMESTERS = 6
28+
const MASTER_SEMESTER_OFFSET = BACHELOR_SEMESTERS
29+
const MASTER_SEMESTERS = 4
1730

1831
export const MembershipWriteFormSchema = MembershipWriteSchema.superRefine((data, ctx) => {
19-
if (data.end && isBefore(data.end, data.start)) {
32+
if (data.end !== null && isBefore(data.end, data.start)) {
33+
ctx.addIssue({
34+
code: "custom",
35+
message: "Sluttdato må være etter startdato.",
36+
path: ["end"],
37+
})
38+
}
39+
40+
if (data.end === null && data.type !== "KNIGHT") {
41+
ctx.addIssue({
42+
code: "custom",
43+
message: "Sluttdato må oppgis for ikke-Ridder-medlemskap.",
44+
path: ["end"],
45+
})
46+
}
47+
48+
if (data.end !== null && data.type === "KNIGHT") {
2049
ctx.addIssue({
2150
code: "custom",
22-
message: "Sluttdato må være etter startdato",
51+
message: "Riddermedlemskap skal ikke ha sluttdato.",
2352
path: ["end"],
2453
})
2554
}
55+
56+
if (data.type === "MASTER_STUDENT") {
57+
if (data.specialization === null) {
58+
ctx.addIssue({
59+
code: "custom",
60+
message: "Spesialisering må oppgis for mastermedlemskap.",
61+
path: ["specialization"],
62+
})
63+
}
64+
65+
if (
66+
data.semester === null ||
67+
data.semester < MASTER_SEMESTER_OFFSET ||
68+
data.semester >= MASTER_SEMESTER_OFFSET + MASTER_SEMESTERS
69+
) {
70+
ctx.addIssue({
71+
code: "custom",
72+
message: `Semester må være oppgitt og minst ${MASTER_SEMESTER_OFFSET + 1} og maks ${MASTER_SEMESTER_OFFSET + MASTER_SEMESTERS} for mastermedlemskap.`,
73+
path: ["semester"],
74+
})
75+
}
76+
}
77+
78+
if (data.specialization !== null && data.type !== "MASTER_STUDENT") {
79+
ctx.addIssue({
80+
code: "custom",
81+
message: "Spesialisering kan kun oppgis for mastermedlemskap.",
82+
path: ["specialization"],
83+
})
84+
}
85+
86+
if (data.type === "BACHELOR_STUDENT") {
87+
if (data.semester === null || data.semester < 0 || data.semester >= BACHELOR_SEMESTERS) {
88+
ctx.addIssue({
89+
code: "custom",
90+
message: `Semester må være oppgitt og minst 1 og maks ${BACHELOR_SEMESTERS} for bachelormedlemskap.`,
91+
path: ["semester"],
92+
})
93+
}
94+
}
95+
96+
if (data.type === "SOCIAL_MEMBER") {
97+
if (data.semester === null || data.semester < 0 || data.semester >= BACHELOR_SEMESTERS + MASTER_SEMESTERS) {
98+
ctx.addIssue({
99+
code: "custom",
100+
message: `Semester må være oppgitt og minst 1 og maks ${BACHELOR_SEMESTERS + MASTER_SEMESTERS} for sosialmedlemskap.`,
101+
path: ["semester"],
102+
})
103+
}
104+
}
26105
})
27106

28107
type MembershipWriteFormSchema = z.infer<typeof MembershipWriteFormSchema>
@@ -61,8 +140,7 @@ export const useMembershipWriteForm = ({
61140
})),
62141
}),
63142
specialization: createSelectInput({
64-
label: "Spesialisering",
65-
description: "Masterspesialisering",
143+
label: "Masterspesialisering",
66144
required: false,
67145
clearable: true,
68146
placeholder: "Velg spesialisering",
@@ -74,48 +152,179 @@ export const useMembershipWriteForm = ({
74152
})),
75153
disabled: false,
76154
}),
77-
start: createDateTimeInput({
78-
label: "Startdato",
79-
required: true,
80-
}),
81-
end: createDateTimeInput({
82-
label: "Sluttdato",
83-
required: true,
84-
}),
85-
semester: createNumberInput({
86-
label: "Semester",
87-
description: (
88-
<Stack gap="xs">
89-
<Text size="xs" c="dimmed">
90-
Hvilket semester medlemskapet innebærer. 0-indeksert.
91-
</Text>
92-
<Stack gap="0.25rem">
93-
<Text size="xs" c="dimmed">
94-
<Code>0</Code> → 1. semester (1. årstrinn)
95-
</Text>
96-
<Text size="xs" c="dimmed">
97-
<Code>1</Code> → 2. semester (1. årstrinn)
98-
</Text>
99-
<Text size="xs" c="dimmed">
100-
<Code>2</Code> → 3. semester (2. årstrinn)
101-
</Text>
102-
<Text size="xs" c="dimmed">
103-
...
104-
</Text>
105-
<Text size="xs" c="dimmed">
106-
<Code>8</Code> → 9. semester (5. årstrinn)
107-
</Text>
108-
<Text size="xs" c="dimmed">
109-
<Code>9</Code> → 10. semester (5. årstrinn)
110-
</Text>
111-
</Stack>
112-
</Stack>
113-
),
114-
required: false,
115-
min: 0,
116-
max: 9,
117-
allowDecimal: false,
118-
}),
155+
semester: ({ state, control }) => {
156+
const name = "semester"
157+
const label = "Semester"
158+
159+
return (
160+
<Controller
161+
control={control}
162+
name={name}
163+
render={({ field }) => {
164+
const zeroIndexedValue = field.value !== null ? field.value : null
165+
const oneIndexedValue = zeroIndexedValue !== null ? zeroIndexedValue + 1 : null
166+
const studyGrade = zeroIndexedValue !== null ? getStudyGrade(zeroIndexedValue) : null
167+
const isAutumnSemester = zeroIndexedValue !== null ? zeroIndexedValue % 2 === 0 : null
168+
169+
return (
170+
<Stack gap="0.25rem">
171+
<NumberInput
172+
label={label}
173+
description={
174+
oneIndexedValue !== null && isAutumnSemester !== null && studyGrade !== null
175+
? `${oneIndexedValue}. semester innebærer ${isAutumnSemester ? "høsten" : "våren"} i ${studyGrade}. årsgang`
176+
: "Ingen semesterverdi"
177+
}
178+
min={1}
179+
max={10}
180+
allowDecimal={false}
181+
value={field.value !== null ? field.value + 1 : undefined}
182+
onChange={(value) => {
183+
const zeroIndexedValue = value !== undefined ? Number(value) - 1 : null
184+
field.onChange(zeroIndexedValue)
185+
}}
186+
error={state.errors[name] && <ErrorMessage errors={state.errors} name={name} />}
187+
/>
188+
<Button
189+
w="fit-content"
190+
fw="normal"
191+
color="gray"
192+
size="compact-xs"
193+
variant="subtle"
194+
onClick={() => field.onChange(null)}
195+
leftSection={<IconX size="0.85rem" />}
196+
styles={{ section: { marginRight: "0.35rem" } }}
197+
>
198+
Fjern verdi
199+
</Button>
200+
</Stack>
201+
)
202+
}}
203+
/>
204+
)
205+
},
206+
start: ({ state, control }) => {
207+
const name = "start"
208+
209+
return (
210+
<Controller
211+
control={control}
212+
name={name}
213+
render={({ field }) => (
214+
<Stack gap="0.25rem">
215+
<DatePickerInput
216+
label="Startdato"
217+
valueFormat="YYYY-MM-DD"
218+
description={
219+
field.value
220+
? isSpringSemester(field.value)
221+
? `Vår ${field.value.getFullYear()}`
222+
: `Høst ${field.value.getFullYear()}`
223+
: undefined
224+
}
225+
style={{ flexGrow: 1 }}
226+
defaultValue={
227+
state.defaultValues?.[name] ?? roundToNearestHours(getCurrentUTC(), { roundingMethod: "ceil" })
228+
}
229+
value={field.value}
230+
onChange={field.onChange}
231+
error={state.errors[name] && <ErrorMessage errors={state.errors} name={name} />}
232+
required
233+
/>
234+
<Group>
235+
<Button
236+
w="fit-content"
237+
fw="normal"
238+
color="gray"
239+
size="compact-xs"
240+
variant="subtle"
241+
onClick={() => field.onChange(getPreviousSemesterStart(field.value ?? getCurrentUTC()))}
242+
leftSection={<IconArrowLeft size="0.85rem" />}
243+
styles={{ section: { marginRight: "0.35rem" } }}
244+
>
245+
Forrige semester
246+
</Button>
247+
<Button
248+
w="fit-content"
249+
fw="normal"
250+
color="gray"
251+
size="compact-xs"
252+
variant="subtle"
253+
onClick={() => field.onChange(getNextSemesterStart(field.value ?? getCurrentUTC()))}
254+
leftSection={<IconArrowRight size="0.85rem" />}
255+
styles={{ section: { marginRight: "0.35rem" } }}
256+
>
257+
Neste semester
258+
</Button>
259+
</Group>
260+
</Stack>
261+
)}
262+
/>
263+
)
264+
},
265+
end: ({ state, control }) => {
266+
const name = "end"
267+
268+
return (
269+
<Controller
270+
control={control}
271+
name={name}
272+
render={({ field }) => (
273+
<Stack gap="0.25rem">
274+
<DatePickerInput
275+
label="Sluttdato"
276+
description={
277+
field.value
278+
? isSpringSemester(field.value)
279+
? `Vår ${field.value.getFullYear()}`
280+
: `Høst ${field.value.getFullYear()}`
281+
: undefined
282+
}
283+
valueFormat="YYYY-MM-DD"
284+
style={{ flexGrow: 1 }}
285+
defaultValue={
286+
state.defaultValues?.[name] ?? roundToNearestHours(getCurrentUTC(), { roundingMethod: "ceil" })
287+
}
288+
value={field.value}
289+
onChange={field.onChange}
290+
error={state.errors[name] && <ErrorMessage errors={state.errors} name={name} />}
291+
rightSection={
292+
<ActionIcon w="fit-content" color="gray" variant="subtle" onClick={() => field.onChange(null)}>
293+
<IconX size="0.85rem" />
294+
</ActionIcon>
295+
}
296+
/>
297+
<Group>
298+
<Button
299+
w="fit-content"
300+
fw="normal"
301+
color="gray"
302+
size="compact-xs"
303+
variant="subtle"
304+
onClick={() => field.onChange(getPreviousSemesterStart(field.value ?? getCurrentUTC()))}
305+
leftSection={<IconArrowLeft size="0.85rem" />}
306+
styles={{ section: { marginRight: "0.35rem" } }}
307+
>
308+
Forrige semester
309+
</Button>
310+
<Button
311+
w="fit-content"
312+
fw="normal"
313+
color="gray"
314+
size="compact-xs"
315+
variant="subtle"
316+
onClick={() => field.onChange(getNextSemesterStart(field.value ?? getCurrentUTC()))}
317+
leftSection={<IconArrowRight size="0.85rem" />}
318+
styles={{ section: { marginRight: "0.35rem" } }}
319+
>
320+
Neste semester
321+
</Button>
322+
</Group>
323+
</Stack>
324+
)}
325+
/>
326+
)
327+
},
119328
},
120329
})
121330
}

0 commit comments

Comments
 (0)