Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add offlines and s3 integration #683

Merged
merged 33 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5f968e3
add offlines, without s3 integration
henrikskog Oct 30, 2023
6c89aa1
lint
henrikskog Oct 30, 2023
86954a2
import :|\
henrikskog Oct 30, 2023
bc6563f
rename from wrong file name
henrikskog Oct 30, 2023
6ffc8f2
schema changes
henrikskog Nov 3, 2023
be55582
Merge branch 'main' into feature/dot-399-create-dashboard-page-for-of…
henrikskog Nov 3, 2023
03bdd5a
Merge branch 'main' into feature/dot-399-create-dashboard-page-for-of…
henrikskog Nov 3, 2023
17b8f1a
working handler
henrikskog Nov 3, 2023
9c79f1e
start integrating s3
henrikskog Nov 4, 2023
2e361f8
add upload pdf to s3
henrikskog Nov 4, 2023
0c6622a
move s3 handler to core and clean up
henrikskog Nov 7, 2023
d711d2d
fix dashboard
henrikskog Nov 7, 2023
a1fbee3
fix wrong method signature
henrikskog Nov 7, 2023
d77501d
rename to file/image_url for clarity
henrikskog Nov 7, 2023
b9899c8
clean up renaming mistake in #680
henrikskog Nov 7, 2023
0eaef43
fix type signature issue that breaks type check
henrikskog Nov 7, 2023
640d4ba
Merge branch 'main' into feature/dot-399-create-dashboard-page-for-of…
henrikskog Nov 7, 2023
a54311d
clean up file uploading code
henrikskog Nov 7, 2023
ab64304
fix import
henrikskog Nov 7, 2023
e5b5254
fix key error in table after renaming
henrikskog Nov 7, 2023
c8282a2
?? instead of ||, typescript:S101
henrikskog Nov 7, 2023
c25f1fb
use mantine link instead of native
henrikskog Nov 7, 2023
33d404a
fix problems raised in review
henrikskog Nov 8, 2023
fab1b17
set updatedAt to current date on update
henrikskog Nov 8, 2023
0745600
fix event update not setting updatedAt
henrikskog Nov 8, 2023
51a10bf
address review comments
henrikskog Nov 9, 2023
5a948d1
Merge branch 'main' into feature/dot-399-create-dashboard-page-for-of…
henrikskog Nov 10, 2023
2421b16
update lock file
henrikskog Nov 10, 2023
cc506cd
File is not available in nodejs
henrikskog Nov 10, 2023
ec840e3
fix: code not updated to collections system
henrikskog Nov 10, 2023
c02e6ee
Merge branch 'fix/committees-query' into feature/dot-399-create-dashb…
henrikskog Nov 10, 2023
7b51e1f
use File derived from Buffer
henrikskog Nov 10, 2023
592d03c
adapt code to run in nodejs
henrikskog Nov 10, 2023
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
21 changes: 21 additions & 0 deletions apps/dashboard/src/app/(dashboard)/offline/[id]/edit-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { FC } from "react"
import { useOfflineWriteForm } from "../write-form"
import { useOfflineDetailsContext } from "./provider"
import { useEditOfflineMutation } from "../../../../modules/offline/mutations/use-edit-offline-mutation"

export const OfflineEditCard: FC = () => {
const { offline } = useOfflineDetailsContext()
const edit = useEditOfflineMutation()

const FormComponent = useOfflineWriteForm({
label: "Oppdater",
onSubmit: (data) => {
edit.mutate({
id: offline.id,
input: data,
})
},
defaultValues: offline,
})
return <FormComponent />
}
19 changes: 19 additions & 0 deletions apps/dashboard/src/app/(dashboard)/offline/[id]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use client"
Fixed Show fixed Hide fixed
Dismissed Show dismissed Hide dismissed

import { Loader } from "@mantine/core"
import { PropsWithChildren } from "react"
import { trpc } from "../../../../utils/trpc"
import { OfflineDetailsContext } from "./provider"

export default function OfflineDetailsLayout({ children, params }: PropsWithChildren<{ params: { id: string } }>) {
const { data, isLoading } = trpc.offline.get.useQuery(params.id)
return (
<>
{isLoading || !data ? (
<Loader />
) : (
<OfflineDetailsContext.Provider value={{ offline: data }}>{children}</OfflineDetailsContext.Provider>
)}
</>
)
}
44 changes: 44 additions & 0 deletions apps/dashboard/src/app/(dashboard)/offline/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use client"

Check warning

Code scanning / CodeQL

Unknown directive Warning

Unknown directive: 'use client'.

import { Icon } from "@iconify/react"
import { Box, CloseButton, Group, Tabs, Title } from "@mantine/core"
import { useRouter } from "next/navigation"
import { OfflineEditCard } from "./edit-card"
import { useOfflineDetailsContext } from "./provider"

const SIDEBAR_LINKS = [
{
icon: "tabler:building-warehouse",
label: "Info",
slug: "info",
component: OfflineEditCard,
},
] as const

export default function OfflineDetailsPage() {
const { offline } = useOfflineDetailsContext()
const router = useRouter()
return (
<Box p="md">
<Group>
<CloseButton onClick={() => router.back()} />
<Title>{offline.title}</Title>
</Group>

<Tabs defaultValue={SIDEBAR_LINKS[0].slug}>
<Tabs.List>
{SIDEBAR_LINKS.map(({ label, icon, slug }) => (
<Tabs.Tab key={slug} value={slug} leftSection={<Icon icon={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>
)
}
17 changes: 17 additions & 0 deletions apps/dashboard/src/app/(dashboard)/offline/[id]/provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"use client"
Fixed Show fixed Hide fixed

Check warning

Code scanning / CodeQL

Unknown directive Warning

Unknown directive: 'use client'.

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

/** Context consisting of everything required to use and render the form */
export const OfflineDetailsContext = createContext<{
offline: Offline
} | null>(null)

export const useOfflineDetailsContext = () => {
const ctx = useContext(OfflineDetailsContext)
if (ctx === null) {
throw new Error("useOfflineDetailsContext called without Provider in tree")
}
return ctx
}
35 changes: 35 additions & 0 deletions apps/dashboard/src/app/(dashboard)/offline/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"use client"

Check warning

Code scanning / CodeQL

Unknown directive Warning

Unknown directive: 'use client'.

import { Icon } from "@iconify/react"
import { Button, ButtonGroup, Card, Group, Skeleton, Stack } from "@mantine/core"
import { GenericTable } from "../../../components/GenericTable"
import { useOfflineAllQuery } from "../../../modules/offline/queries/use-offlines-all-query"
import { useCreateOfflineModal } from "../../../modules/offline/modals/create-offline-modal"
import { useOfflineTable } from "../../../modules/offline/use-offline-table"

export default function OfflinePage() {
const { offlines, isLoading: isOfflinesLoading } = useOfflineAllQuery()
const open = useCreateOfflineModal()
const table = useOfflineTable({ data: offlines })

return (
<Skeleton visible={isOfflinesLoading}>
<Stack>
<Card withBorder>
<GenericTable table={table} />
</Card>
<Group justify="space-between">
<Button onClick={open}>Legg inn ny Offline</Button>
<ButtonGroup>
<Button variant="subtle">
<Icon icon="tabler:caret-left" />
</Button>
<Button variant="subtle">
<Icon icon="tabler:caret-right" />
</Button>
</ButtonGroup>
</Group>
</Stack>
</Skeleton>
)
}
45 changes: 45 additions & 0 deletions apps/dashboard/src/app/(dashboard)/offline/write-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { createDateTimeInput, createTextInput, useFormBuilder } from "src/app/form"
import { z } from "zod"
import { OfflineWriteSchema } from "../../../../../../packages/types/src/offline"

const OFFLINE_FORM_DEFAULT_VALUES: Partial<FormValidationSchema> = {}

type UseOfflineWriteFormProps = {
onSubmit: (data: FormValidationSchema) => void
defaultValues?: Partial<FormValidationSchema>
label?: string
}

export const FormValidationSchema = OfflineWriteSchema
type FormValidationSchema = z.infer<typeof FormValidationSchema>

export const useOfflineWriteForm = ({
onSubmit,
label = "Registrer",
defaultValues = OFFLINE_FORM_DEFAULT_VALUES,
}: UseOfflineWriteFormProps) => {
return useFormBuilder({
schema: FormValidationSchema,
defaultValues,
onSubmit,
label,
fields: {
title: createTextInput({
label: "Tittel",
placeholder: "Offline #50",
}),
published: createDateTimeInput({
label: "Utgivelsesdato",
placeholder: "2023-10-05",
}),
file: createTextInput({
label: "Fil",
placeholder: "s3 link",
}),
image: createTextInput({
label: "Bilde",
placeholder: "s3 link",
}),
},
})
}
2 changes: 2 additions & 0 deletions apps/dashboard/src/app/ModalProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { FC, PropsWithChildren } from "react"
import { CreateCompanyModal } from "src/modules/company/modals/create-company-modal"
import { CreateEventModal } from "src/modules/event/modals/create-event-modal"
import { CreateJobListingModal } from "src/modules/job-listing/modals/create-job-listing-modal"
import { CreateOfflineModal } from "../modules/offline/modals/create-offline-modal"

const modals = {
"event/create": CreateEventModal,
"jobListing/create": CreateJobListingModal,
"company/create": CreateCompanyModal,
"offline/create": CreateOfflineModal,
} as const

export const ModalProvider: FC<PropsWithChildren> = ({ children }) => {
Expand Down
25 changes: 25 additions & 0 deletions apps/dashboard/src/modules/offline/modals/create-offline-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { FC } from "react"
import { ContextModalProps, modals } from "@mantine/modals"
import { useCreateOfflineMutation } from "../mutations/use-create-offline-mutation"
import { useOfflineWriteForm } from "../../../app/(dashboard)/offline/write-form"

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

export const useCreateOfflineModal = () => {
return () =>
modals.openContextModal({
modal: "offline/create",
title: "Opprett ny Offline",
innerProps: {},
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useQueryNotification } from "../../../app/notifications"
import { trpc } from "../../../utils/trpc"
import { useRouter } from "next/navigation"

export const useCreateOfflineMutation = () => {
const utils = trpc.useContext()
const router = useRouter()
const notification = useQueryNotification()
return trpc.offline.create.useMutation({
onMutate: () => {
notification.loading({
title: "Oppretter...",
message: "Vellykkett opprettelse. Du blir sendt til ressursen.",
})
},
onSuccess: (data) => {
notification.complete({
title: "Opprettet",
message: "Ressursen har blitt opprettet.",
})
utils.offline.all.invalidate()
router.push(`/job-listing/${data.id}`)
},
onError: (err) => {
notification.fail({
title: "Feil oppsto",
message: `En feil oppsto under opprettelsen: ${err.toString()}.`,
})
},
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useQueryNotification } from "../../../app/notifications"
import { trpc } from "../../../utils/trpc"

export const useEditOfflineMutation = () => {
const notification = useQueryNotification()
const utils = trpc.useContext()
return trpc.offline.edit.useMutation({
onMutate: () => {
notification.loading({
title: "Oppdaterer",
message: "Ressursen blir oppdatert.",
})
},
onSuccess: (data) => {
notification.complete({
title: "Ressursen oppdatert",
message: `Ressursen "${data.title}" har blitt oppdatert.`,
})
utils.offline.all.invalidate()
},
onError: (err) => {
notification.fail({
title: "Feil oppsto",
message: `En feil oppsto under oppdatering: ${err.toString()}.`,
})
},
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { trpc } from "../../../utils/trpc"

export const useOfflineAllQuery = () => {
const { data: offlines = [], ...query } = trpc.offline.all.useQuery({ take: 999 })
return { offlines, ...query }
}
46 changes: 46 additions & 0 deletions apps/dashboard/src/modules/offline/use-offline-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"use client"
Fixed Show fixed Hide fixed

Check warning

Code scanning / CodeQL

Unknown directive Warning

Unknown directive: 'use client'.

import { Offline } from "@dotkomonline/types"
import { Anchor, Text } from "@mantine/core"
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table"
import Link from "next/link"
import { useMemo } from "react"
import { formatDate } from "../../utils/format"

interface Props {
data: Offline[]
}

export const useOfflineTable = ({ data }: Props) => {
const columnHelper = createColumnHelper<Offline>()
const columns = useMemo(
() => [
columnHelper.accessor("title", {
header: () => "Tittel",
cell: (info) => info.getValue(),
}),
columnHelper.accessor("published", {
header: () => "Utgivelsesdato",
cell: (info) => {
return <Text>{formatDate(info.getValue())}</Text>
},
}),
columnHelper.accessor((evt) => evt, {
id: "actions",
header: () => "Detaljer",
cell: (info) => (
<Anchor component={Link} size="sm" href={`/offline/${info.getValue().id}`}>
Se mer
</Anchor>
),
}),
],
[columnHelper]
)

return useReactTable({
data: data,
getCoreRowModel: getCoreRowModel(),
columns,
})
}
8 changes: 8 additions & 0 deletions apps/db-migrator/src/fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { events } from "./fixtures/event"
import { eventCompany } from "./fixtures/event-company"
import { jobListingLocationLinks, jobListingLocations, jobListings } from "./fixtures/job-listing"
import { marks } from "./fixtures/mark"
import { offlines } from "./fixtures/offline"
import { personalMarks } from "./fixtures/personal-mark"
import { products } from "./fixtures/product"
import { productPaymentProviders } from "./fixtures/product-payment-provider"
Expand Down Expand Up @@ -194,4 +195,11 @@ export const runFixtures = async () => {
.returning("id")
.onConflict((oc) => oc.column("id").doNothing())
.execute()

await db
.insertInto("offline")
.values(offlines)
.returning("id")
.onConflict((oc) => oc.column("id").doNothing())
.execute()
}
19 changes: 19 additions & 0 deletions apps/db-migrator/src/fixtures/offline.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Database } from "@dotkomonline/db"
import { Insertable } from "kysely"

export const offlines: Insertable<Database["offline"]>[] = [
{
id: "01HD77R4Y4S3WJ44NZ8029VP4P",
title: "Job at Bekk",
published: new Date("2023-10-09T10:00:00+02:00"),
file: "https://bekk.no",
image: "https://bekk.no",
},
{
id: "01HD77R4Y4S3WJ44NZ8029VP4C",
title: "Job at Bekk 2",
published: new Date("2023-10-09T10:00:00+02:00"),
file: "https://bekk.no",
image: "https://bekk.no",
},
]
Loading