Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"use client"

import { GenericTable } from "@/components/GenericTable"
import { DateTooltip } from "@/components/DateTooltip"
import { mapNotificationPayloadTypeToLabel, mapNotificationTypeToLabel, type Notification } from "@dotkomonline/rpc"
import { Anchor, Box, Button, Skeleton, Stack, Title } from "@mantine/core"
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table"
import Link from "next/link"
import { type FC, useMemo } from "react"
import { useNotificationsByPayloadQuery } from "../queries"
import { useEventContext } from "./provider"
import { openCreateEventNotificationModal } from "../components/create-event-notification-modal"

export const NotificationsPage: FC = () => {
const { event } = useEventContext()
const { notifications, isLoading } = useNotificationsByPayloadQuery("EVENT", event.id)

const columnHelper = createColumnHelper<Notification>()

const columns = useMemo(
() => [
columnHelper.accessor((notification) => notification.title, {
id: "title",
header: () => "Tittel",
sortingFn: "alphanumeric",
cell: (info) => (
<Anchor component={Link} size="sm" href={`/varslinger/${info.row.original.id}`}>
{info.getValue()}
</Anchor>
),
}),
columnHelper.accessor((notification) => notification.shortDescription, {
id: "shortDescription",
header: () => "Kort beskrivelse",
cell: (info) => info.getValue(),
sortingFn: "alphanumeric",
}),
columnHelper.accessor((notification) => notification.type, {
id: "type",
header: () => "Type",
cell: (info) => mapNotificationTypeToLabel(info.getValue()),
sortingFn: "alphanumeric",
}),
columnHelper.accessor((notification) => notification.payloadType, {
id: "payloadType",
header: () => "Payload type",
cell: (info) => mapNotificationPayloadTypeToLabel(info.getValue()),
sortingFn: "alphanumeric",
}),
columnHelper.accessor((notification) => notification.createdAt, {
id: "createdAt",
header: () => "Opprettet",
cell: (info) => <DateTooltip date={info.getValue()} />,
sortingFn: "datetime",
}),
],
[columnHelper]
)

const tableOptions = useMemo(
() => ({
data: notifications,
getCoreRowModel: getCoreRowModel(),
columns,
}),
[notifications, columns]
)

const table = useReactTable(tableOptions)

return (
<Skeleton visible={isLoading}>
<Stack gap="lg">
<Box>
<Title order={3}>Opprett varsling</Title>
<Button mt="md" onClick={openCreateEventNotificationModal({ eventId: event.id })}>
Legg til ny varsling
</Button>
</Box>

<Box>
<Title order={2}>Varslinger</Title>
<GenericTable table={table} />
</Box>
</Stack>
</Skeleton>
)
}
8 changes: 8 additions & 0 deletions apps/dashboard/src/app/(internal)/arrangementer/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
IconSelector,
IconTrash,
IconUser,
IconBell,
} from "@tabler/icons-react"
import { useRouter, useSearchParams } from "next/navigation"
import { useDeleteEventMutation } from "../mutations"
Expand All @@ -27,6 +28,7 @@ import { FeedbackPage } from "./feedback-page"
import { PaymentPage } from "./payment-page"
import { useEventContext } from "./provider"
import { SelectionsPage } from "./selections-page"
import { NotificationsPage } from "./notification-page"

const SIDEBAR_LINKS = [
{
Expand Down Expand Up @@ -65,6 +67,12 @@ const SIDEBAR_LINKS = [
slug: "betaling",
component: PaymentPage,
},
{
icon: IconBell,
label: "Varslinger",
slug: "varslinger",
component: NotificationsPage,
},
]

export default function EventWithAttendancesPage() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useNotificationWriteForm } from "@/app/(internal)/varslinger/write-form"
import { type ContextModalProps, modals } from "@mantine/modals"
import type { FC } from "react"
import { useCreateEventNotificationMutation } from "../mutations"

interface CreateEventNotificationModalProps {
eventId: string
}

export const CreateEventNotificationModal: FC<ContextModalProps<CreateEventNotificationModalProps>> = ({
context,
id,
innerProps: { eventId },
}) => {
const close = () => context.closeModal(id)
const create = useCreateEventNotificationMutation(eventId)

const FormComponent = useNotificationWriteForm({
defaultValues: {
recipientIds: [],
taskId: null,
payloadType: "EVENT",
payload: eventId,
},
onSubmit: (data) => {
create.mutate(data)
close()
},
})

return <FormComponent />
}

export const openCreateEventNotificationModal =
({ eventId }: CreateEventNotificationModalProps) =>
() =>
modals.openContextModal({
modal: "event/notification/create",
title: "Legg inn ny varsling",
size: "lg",
innerProps: { eventId },
})
31 changes: 31 additions & 0 deletions apps/dashboard/src/app/(internal)/arrangementer/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,37 @@ export const useUpdateAttendeeReservedMutation = () => {
)
}

export const useCreateEventNotificationMutation = (eventId: string) => {
const trpc = useTRPC()
const queryClient = useQueryClient()
const notification = useQueryNotification()
return useMutation(
trpc.notification.create.mutationOptions({
onMutate: () => {
notification.loading({
title: "Lager varsling...",
message: "Varslingen blir opprettet.",
})
},
onSuccess: async (data) => {
await queryClient.invalidateQueries({
queryKey: trpc.notification.findManyByPayload.queryKey({ payloadType: "EVENT", payload: eventId }),
})
notification.complete({
title: "Varsling opprettet",
message: `Varslingen "${data.title}" har blitt opprettet.`,
})
},
onError: (err) => {
notification.fail({
title: "Feil oppsto",
message: `En feil oppsto under opprettelse av varslingen: ${err.toString()}.`,
})
},
})
)
}

export const useEventFileUploadMutation = () => {
const trpc = useTRPC()

Expand Down
8 changes: 8 additions & 0 deletions apps/dashboard/src/app/(internal)/arrangementer/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { type SkipToken, useInfiniteQuery, useQuery } from "@tanstack/react-quer
import { useTRPC } from "@/lib/trpc-client"
import type { Pageable } from "@dotkomonline/utils"
import { useMemo } from "react"
import type { NotificationPayloadType } from "@dotkomonline/rpc"

interface UseEventAllQueryProps {
filter: EventFilterQuery
Expand Down Expand Up @@ -90,3 +91,10 @@ export const useFeedbackAnswersGetQuery = (formId: FeedbackFormId | SkipToken) =
const trpc = useTRPC()
return useQuery(trpc.event.feedback.getAllAnswers.queryOptions(formId))
}

export const useNotificationsByPayloadQuery = (payloadType: NotificationPayloadType, payload: string) => {
const trpc = useTRPC()
const { data, ...query } = useQuery(trpc.notification.findManyByPayload.queryOptions({ payloadType, payload }))

return { notifications: useMemo(() => data?.items ?? [], [data]), ...query }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"use client"

import { GenericTable } from "@/components/GenericTable"
import { DateTooltip } from "@/components/DateTooltip"
import { mapNotificationPayloadTypeToLabel, mapNotificationTypeToLabel, type Notification } from "@dotkomonline/rpc"
import { Anchor, Box, Button, Skeleton, Stack, Title } from "@mantine/core"
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table"
import Link from "next/link"
import { type FC, useMemo } from "react"
import { useNotificationsByPayloadQuery } from "../../arrangementer/queries"
import { openCreateGroupNotificationModal } from "../modals/create-group-notification-modal"
import { useGroupDetailsContext } from "./provider"

export const GroupNotificationPage: FC = () => {
const { group } = useGroupDetailsContext()
const { notifications, isLoading } = useNotificationsByPayloadQuery("GROUP", group.slug)

const columnHelper = createColumnHelper<Notification>()

const columns = useMemo(
() => [
columnHelper.accessor((notification) => notification.title, {
id: "title",
header: () => "Tittel",
sortingFn: "alphanumeric",
cell: (info) => (
<Anchor component={Link} size="sm" href={`/varslinger/${info.row.original.id}`}>
{info.getValue()}
</Anchor>
),
}),
columnHelper.accessor((notification) => notification.shortDescription, {
id: "shortDescription",
header: () => "Kort beskrivelse",
cell: (info) => info.getValue(),
sortingFn: "alphanumeric",
}),
columnHelper.accessor((notification) => notification.type, {
id: "type",
header: () => "Type",
cell: (info) => mapNotificationTypeToLabel(info.getValue()),
sortingFn: "alphanumeric",
}),
columnHelper.accessor((notification) => notification.payloadType, {
id: "payloadType",
header: () => "Payload type",
cell: (info) => mapNotificationPayloadTypeToLabel(info.getValue()),
sortingFn: "alphanumeric",
}),
columnHelper.accessor((notification) => notification.createdAt, {
id: "createdAt",
header: () => "Opprettet",
cell: (info) => <DateTooltip date={info.getValue()} />,
sortingFn: "datetime",
}),
],
[columnHelper]
)

const tableOptions = useMemo(
() => ({
data: notifications,
getCoreRowModel: getCoreRowModel(),
columns,
}),
[notifications, columns]
)

const table = useReactTable(tableOptions)

return (
<Skeleton visible={isLoading}>
<Stack gap="lg">
<Box>
<Title order={3}>Opprett varsling</Title>
<Button mt="md" onClick={openCreateGroupNotificationModal({ groupSlug: group.slug })}>
Legg til ny varsling
</Button>
</Box>

<Box>
<Title order={2}>Varslinger</Title>
<GenericTable table={table} />
</Box>
</Stack>
</Skeleton>
)
}
9 changes: 8 additions & 1 deletion apps/dashboard/src/app/(internal)/grupper/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"use client"

import { Box, CloseButton, Group, Tabs, Title } from "@mantine/core"
import { IconCircles, IconListDetails, IconUsers, IconWheelchair } from "@tabler/icons-react"
import { IconCircles, IconListDetails, IconBell, IconUsers, IconWheelchair } from "@tabler/icons-react"
import { useRouter, useSearchParams } from "next/navigation"
import { GroupEditCard } from "./edit-card"
import { GroupEventPage } from "./group-event-page"
import { GroupNotificationPage } from "./group-notification-page"
import { GroupMembersPage } from "./members-page"
import { useGroupDetailsContext } from "./provider"
import { GroupRolesPage } from "./roles-page"
Expand Down Expand Up @@ -34,6 +35,12 @@ const SIDEBAR_LINKS = [
slug: "arrangementer",
component: GroupEventPage,
},
{
icon: IconBell,
label: "Varslinger",
slug: "varslinger",
component: GroupNotificationPage,
},
] as const

export default function GroupDetailsPage() {
Expand Down
Loading
Loading