Skip to content

Commit 68c1c3c

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

File tree

11 files changed

+449
-146
lines changed

11 files changed

+449
-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 og ikke slutt- eller startdato 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 og ikke slutt- eller startdato for å endre årstrinn.
29+
</Text>
30+
<FormComponent />
31+
</Stack>
32+
)
2533
}
2634

2735
export const useEditMembershipModal =
Lines changed: 207 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,62 @@ 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"
1726

1827
export const MembershipWriteFormSchema = MembershipWriteSchema.superRefine((data, ctx) => {
19-
if (data.end && isBefore(data.end, data.start)) {
28+
if (data.end !== null && isBefore(data.end, data.start)) {
2029
ctx.addIssue({
2130
code: "custom",
22-
message: "Sluttdato må være etter startdato",
31+
message: "Sluttdato må være etter startdato.",
2332
path: ["end"],
2433
})
2534
}
35+
36+
if (data.end === null && data.type !== "KNIGHT") {
37+
ctx.addIssue({
38+
code: "custom",
39+
message: "Sluttdato må oppgis for ikke-Ridder-medlemskap.",
40+
path: ["end"],
41+
})
42+
}
43+
44+
if (data.end !== null && data.type === "KNIGHT") {
45+
ctx.addIssue({
46+
code: "custom",
47+
message: "Riddermedlemskap skal ikke ha sluttdato.",
48+
path: ["end"],
49+
})
50+
}
51+
52+
if (data.specialization !== null && data.type !== "MASTER_STUDENT") {
53+
ctx.addIssue({
54+
code: "custom",
55+
message: "Spesialisering kan kun oppgis for mastermedlemskap.",
56+
path: ["specialization"],
57+
})
58+
}
59+
60+
if (data.specialization === null && data.type === "MASTER_STUDENT") {
61+
ctx.addIssue({
62+
code: "custom",
63+
message: "Spesialisering må oppgis for mastermedlemskap.",
64+
path: ["specialization"],
65+
})
66+
}
2667
})
2768

2869
type MembershipWriteFormSchema = z.infer<typeof MembershipWriteFormSchema>
@@ -61,8 +102,7 @@ export const useMembershipWriteForm = ({
61102
})),
62103
}),
63104
specialization: createSelectInput({
64-
label: "Spesialisering",
65-
description: "Masterspesialisering",
105+
label: "Masterspesialisering",
66106
required: false,
67107
clearable: true,
68108
placeholder: "Velg spesialisering",
@@ -74,48 +114,164 @@ export const useMembershipWriteForm = ({
74114
})),
75115
disabled: false,
76116
}),
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-
}),
117+
semester: ({ state, control }) => {
118+
const name = "semester"
119+
const label = "Semester"
120+
121+
return (
122+
<Controller
123+
control={control}
124+
name={name}
125+
render={({ field }) => {
126+
const oneIndexedValue = field.value !== null ? field.value + 1 : null
127+
const studyGrade = field.value !== null ? getStudyGrade(field.value) : null
128+
const even = field.value !== null ? field.value % 2 === 0 : null
129+
130+
return (
131+
<NumberInput
132+
label={label}
133+
description={
134+
oneIndexedValue !== null
135+
? `${oneIndexedValue}. semester innebærer ${even ? "våren" : "høsten"} i ${studyGrade}. årsgang`
136+
: "Velg en verdi"
137+
}
138+
min={1}
139+
max={10}
140+
allowDecimal={false}
141+
value={field.value !== null ? field.value + 1 : undefined}
142+
onChange={(value) => {
143+
const zeroIndexedValue = value !== undefined ? Number(value) - 1 : null
144+
field.onChange(zeroIndexedValue)
145+
}}
146+
error={state.errors[name] && <ErrorMessage errors={state.errors} name={name} />}
147+
/>
148+
)
149+
}}
150+
/>
151+
)
152+
},
153+
start: ({ state, control }) => {
154+
const name = "start"
155+
156+
return (
157+
<Controller
158+
control={control}
159+
name={name}
160+
render={({ field }) => (
161+
<Stack gap="0.25rem">
162+
<DatePickerInput
163+
label="Startdato"
164+
valueFormat="YYYY-MM-DD"
165+
description={
166+
field.value
167+
? isSpringSemester(field.value)
168+
? `Vår ${field.value.getFullYear()}`
169+
: `Høst ${field.value.getFullYear()}`
170+
: undefined
171+
}
172+
style={{ flexGrow: 1 }}
173+
defaultValue={
174+
state.defaultValues?.[name] ?? roundToNearestHours(getCurrentUTC(), { roundingMethod: "ceil" })
175+
}
176+
value={field.value}
177+
onChange={field.onChange}
178+
error={state.errors[name] && <ErrorMessage errors={state.errors} name={name} />}
179+
required
180+
/>
181+
<Group>
182+
<Button
183+
w="fit-content"
184+
fw="normal"
185+
color="gray"
186+
size="compact-xs"
187+
variant="subtle"
188+
onClick={() => field.onChange(getPreviousSemesterStart(field.value ?? getCurrentUTC()))}
189+
leftSection={<IconArrowLeft size="0.85rem" />}
190+
styles={{ section: { marginRight: "0.35rem" } }}
191+
>
192+
Forrige semester
193+
</Button>
194+
<Button
195+
w="fit-content"
196+
fw="normal"
197+
color="gray"
198+
size="compact-xs"
199+
variant="subtle"
200+
onClick={() => field.onChange(getNextSemesterStart(field.value ?? getCurrentUTC()))}
201+
leftSection={<IconArrowRight size="0.85rem" />}
202+
styles={{ section: { marginRight: "0.35rem" } }}
203+
>
204+
Neste semester
205+
</Button>
206+
</Group>
207+
</Stack>
208+
)}
209+
/>
210+
)
211+
},
212+
end: ({ state, control }) => {
213+
const name = "end"
214+
215+
return (
216+
<Controller
217+
control={control}
218+
name={name}
219+
render={({ field }) => (
220+
<Stack gap="0.25rem">
221+
<DatePickerInput
222+
label="Sluttdato"
223+
description={
224+
field.value
225+
? isSpringSemester(field.value)
226+
? `Vår ${field.value.getFullYear()}`
227+
: `Høst ${field.value.getFullYear()}`
228+
: undefined
229+
}
230+
valueFormat="YYYY-MM-DD"
231+
style={{ flexGrow: 1 }}
232+
defaultValue={
233+
state.defaultValues?.[name] ?? roundToNearestHours(getCurrentUTC(), { roundingMethod: "ceil" })
234+
}
235+
value={field.value}
236+
onChange={field.onChange}
237+
error={state.errors[name] && <ErrorMessage errors={state.errors} name={name} />}
238+
rightSection={
239+
<ActionIcon w="fit-content" color="gray" variant="subtle" onClick={() => field.onChange(null)}>
240+
<IconX size="0.85rem" />
241+
</ActionIcon>
242+
}
243+
/>
244+
<Group>
245+
<Button
246+
w="fit-content"
247+
fw="normal"
248+
color="gray"
249+
size="compact-xs"
250+
variant="subtle"
251+
onClick={() => field.onChange(getPreviousSemesterStart(field.value ?? getCurrentUTC()))}
252+
leftSection={<IconArrowLeft size="0.85rem" />}
253+
styles={{ section: { marginRight: "0.35rem" } }}
254+
>
255+
Forrige semester
256+
</Button>
257+
<Button
258+
w="fit-content"
259+
fw="normal"
260+
color="gray"
261+
size="compact-xs"
262+
variant="subtle"
263+
onClick={() => field.onChange(getNextSemesterStart(field.value ?? getCurrentUTC()))}
264+
leftSection={<IconArrowRight size="0.85rem" />}
265+
styles={{ section: { marginRight: "0.35rem" } }}
266+
>
267+
Neste semester
268+
</Button>
269+
</Group>
270+
</Stack>
271+
)}
272+
/>
273+
)
274+
},
119275
},
120276
})
121277
}

0 commit comments

Comments
 (0)