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
18 changes: 18 additions & 0 deletions apps/dashboard/src/app/(internal)/varslinger/[id]/edit-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { FC } from "react"
import { useEditNotificationMutation } from "../mutations"
import { useNotificationWriteForm } from "../write-form"
import { useNotificationDetailsContext } from "./provider"
export const NotificationEditCard: FC = () => {
const { notification } = useNotificationDetailsContext()
const edit = useEditNotificationMutation()

const FormComponent = useNotificationWriteForm({
label: "Oppdater varsling",
onSubmit: (data) => {
const { ...notificationData } = data
edit.mutate({ id: notification.id, input: notificationData})
},
defaultValues: { ...notification }
})
return <FormComponent />
}
31 changes: 31 additions & 0 deletions apps/dashboard/src/app/(internal)/varslinger/[id]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"use client"
import { Loader } from "@mantine/core"
import { type PropsWithChildren, use, useMemo } from "react"
import { NotificationDetailsContext } from "./provider"

import { useTRPC } from "@/lib/trpc-client"
import { useQuery } from "@tanstack/react-query"

export default function NotificationDetailsLayout({
children,
params,
}: PropsWithChildren<{ params: Promise<{ id: string }> }>) {
const trpc = useTRPC()
const { id } = use(params)
const { data, isLoading } = useQuery(trpc.notification.get.queryOptions(id))
const value = useMemo(
() =>
!data || isLoading
? null
: {
notification: data,
},
[data, isLoading]
)

if (value === null) {
return <Loader />
}

return <NotificationDetailsContext.Provider value={value}>{children}</NotificationDetailsContext.Provider>
}
54 changes: 54 additions & 0 deletions apps/dashboard/src/app/(internal)/varslinger/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"use client"

import { Box, CloseButton, Group, Tabs, Title } from "@mantine/core"
import { IconPhoto } from "@tabler/icons-react"
import { useRouter, useSearchParams } from "next/navigation"
import { NotificationEditCard } from "./edit-card"
import { useNotificationDetailsContext } from "./provider"

const SIDEBAR_LINKS = [
{
icon: IconPhoto,
label: "Info",
slug: "info",
component: NotificationEditCard,
},
] as const

export default function NotificationDetailsPage() {
const { notification } = useNotificationDetailsContext()
const router = useRouter()

const searchParams = useSearchParams()
const currentTab = searchParams.get("tab") || SIDEBAR_LINKS[0].slug

const handleTabChange = (value: string | null) => {
const params = new URLSearchParams(searchParams.toString())
params.set("tab", value ?? SIDEBAR_LINKS[0].slug)
router.replace(`/varsler/${notification.id}?${params.toString()}`)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

varslinger

}

return (
<Box>
<Group>
<CloseButton onClick={() => router.back()} />
<Title>{notification.title}</Title>
</Group>

<Tabs defaultValue={currentTab} onChange={handleTabChange}>
<Tabs.List>
{SIDEBAR_LINKS.map(({ label, icon: Icon, slug }) => (
<Tabs.Tab key={slug} value={slug} leftSection={<Icon width={14} height={14} />}>
{label}
</Tabs.Tab>
))}
</Tabs.List>
{SIDEBAR_LINKS.map(({ slug, component: Component }) => (
<Tabs.Panel mt="md" key={slug} value={slug}>
<Component />
</Tabs.Panel>
))}
</Tabs>
</Box>
)
}
16 changes: 16 additions & 0 deletions apps/dashboard/src/app/(internal)/varslinger/[id]/provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use client"

import type { Notification } from "@dotkomonline/types"
import { createContext, useContext } from "react"

export const NotificationDetailsContext = createContext<{
notification: Notification
} | null>(null)

export const useNotificationDetailsContext = () => {
const ctx = useContext(NotificationDetailsContext)
if (ctx === null) {
throw new Error("useNotificationDetailsContext called without Provider in tree")
}
return ctx
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { GenericTable } from "@/components/GenericTable"
import { Anchor } from "@mantine/core"
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table"
import Link from "next/link"
import { useMemo } from "react"
import { mapNotificationPayloadTypeToLabel, mapNotificationTypeToLabel, Notification } from "node_modules/@dotkomonline/rpc/src/modules/notification/notification"
import { DateTooltip } from "@/components/DateTooltip"

interface AllNotificationsTableProps {
notifications: Notification[]
}

export const AllNotificationsTable = ({ notifications }: AllNotificationsTableProps) => {
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={`/varsler/${info.row.original.id}`}>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

varslinger

{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 (
<GenericTable
table = {table}
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { type ContextModalProps, modals } from "@mantine/modals"
import type { FC } from "react"
import { useCreateNotificationMutation } from "../mutations"
import { useNotificationWriteForm } from "../write-form"

export const CreateNotificationModal: FC<ContextModalProps> = ({ context, id }) => {
const close = () => context.closeModal(id)
const create = useCreateNotificationMutation()
const FormComponent = useNotificationWriteForm({
onSubmit: (data) => {
create.mutate(
data
),
close()
},
})
return <FormComponent />
}

export const useCreateNotificationModal = () => () =>
modals.openContextModal({
modal: "notification/create",
title: "Legg inn ny varsling",
size: "lg",
innerProps: {},
})
67 changes: 67 additions & 0 deletions apps/dashboard/src/app/(internal)/varslinger/mutations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { env } from "@/lib/env"
import { useQueryNotification } from "@/lib/notifications"
import { useTRPC } from "@/lib/trpc-client"
import { useMutation, useQueryClient } from "@tanstack/react-query"

export const useCreateNotificationMutation = () => {
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, og du vil bli videresendt til varslingssiden.",
})
},
onSuccess: async (data) => {
await queryClient.invalidateQueries({ queryKey: trpc.notification.findMany.queryKey() });


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 useEditNotificationMutation = () => {
const trpc = useTRPC()
const queryClient = useQueryClient()
const notification = useQueryNotification()

return useMutation(
trpc.notification.edit.mutationOptions({
onMutate: () => {
notification.loading({
title: "Oppdaterer varsling...",
message: "Varslingen blir oppdatert.",
})
},
onSuccess: async (data) => {
await queryClient.invalidateQueries(trpc.notification.get.queryOptions(data.id))

notification.complete({
title: "Varslingen oppdatert",
message: `Varslingen "${data.title}" har blitt oppdatert.`,
})
},
onError: (err) => {
notification.fail({
title: "Feil oppsto",
message: `En feil oppsto under oppdatering av varslingen: ${err.toString()}.`,
})
},
})
)
}

23 changes: 23 additions & 0 deletions apps/dashboard/src/app/(internal)/varslinger/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use client"

import { Box, Button, Skeleton, Stack } from "@mantine/core"
import { AllNotificationsTable } from "./all-notification-table"
import { useCreateNotificationModal } from "./modals/create-notification"
import { useNotificationAllQuery } from "./queries"


export default function NotificationPage() {
const { notifications, isLoading: isNotificationsLoading } = useNotificationAllQuery()
const open = useCreateNotificationModal()

return (
<Skeleton visible={isNotificationsLoading}>
<Stack>
<Box>
<Button onClick={open}>Opprett varsling</Button>
</Box>
<AllNotificationsTable notifications={notifications} />
</Stack>
</Skeleton>
)
}
18 changes: 18 additions & 0 deletions apps/dashboard/src/app/(internal)/varslinger/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useTRPC } from "@/lib/trpc-client"
import { Pageable } from "@dotkomonline/rpc"
import { useInfiniteQuery } from "@tanstack/react-query"
import { useMemo } from "react"

export const useNotificationAllQuery = (page?: Pageable) => {
const trpc = useTRPC()

const { data, ...query } = useInfiniteQuery({
...trpc.notification.findMany.infiniteQueryOptions({ ...page }),
getNextPageParam: (lastPage) => lastPage.nextCursor,
select: (res) => res.pages.flatMap((p) => p.items),
})

return { notifications: useMemo(() => data ?? [], [data]), ...query }
}


Loading
Loading