update qr settings page to use page action

pull/3/head
TZGyn 2 years ago
parent 9024bd4f04
commit 79ec261c26
Signed by: TZGyn
GPG Key ID: 122EAF77AE81FD4A

Binary file not shown.

@ -14,8 +14,8 @@
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-node": "^2.0.0", "@sveltejs/adapter-node": "^2.0.0",
"@sveltejs/kit": "^2.0.0", "@sveltejs/kit": "^2.5.5",
"@sveltejs/vite-plugin-svelte": "^3.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.2",
"@types/qrcode": "^1.5.5", "@types/qrcode": "^1.5.5",
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.14",
"bun-types": "^1.0.11", "bun-types": "^1.0.11",
@ -26,13 +26,13 @@
"prettier": "^3.1.0", "prettier": "^3.1.0",
"prettier-plugin-svelte": "^3.1.0", "prettier-plugin-svelte": "^3.1.0",
"prettier-plugin-tailwindcss": "^0.5.7", "prettier-plugin-tailwindcss": "^0.5.7",
"svelte": "^4.0.5", "svelte": "^4.2.12",
"svelte-adapter-bun": "^0.5.1", "svelte-adapter-bun": "^0.5.1",
"svelte-check": "^3.4.3", "svelte-check": "^3.4.3",
"tailwindcss": "^3.3.2", "tailwindcss": "^3.3.2",
"tslib": "^2.4.1", "tslib": "^2.4.1",
"typescript": "^5.0.0", "typescript": "^5.0.0",
"vite": "^5.0.0" "vite": "^5.2.8"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
@ -40,10 +40,11 @@
"@prgm/sveltekit-progress-bar": "^2.0.0", "@prgm/sveltekit-progress-bar": "^2.0.0",
"@types/he": "^1.2.3", "@types/he": "^1.2.3",
"apexcharts": "^3.44.0", "apexcharts": "^3.44.0",
"bits-ui": "^0.19.7", "bits-ui": "^0.21.2",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"cmdk-sv": "^0.0.13", "cmdk-sv": "^0.0.13",
"drizzle-orm": "latest", "drizzle-orm": "latest",
"formsnap": "^1.0.0",
"he": "^1.2.0", "he": "^1.2.0",
"lucide-svelte": "^0.356.0", "lucide-svelte": "^0.356.0",
"mode-watcher": "^0.1.2", "mode-watcher": "^0.1.2",
@ -54,6 +55,7 @@
"postgres": "^3.4.3", "postgres": "^3.4.3",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
"svelte-sonner": "^0.3.10", "svelte-sonner": "^0.3.10",
"sveltekit-superforms": "^2.12.2",
"tailwind-merge": "^2.0.0", "tailwind-merge": "^2.0.0",
"tailwind-variants": "^0.1.18", "tailwind-variants": "^0.1.18",
"zod": "^3.22.4" "zod": "^3.22.4"

@ -1,9 +1,10 @@
<script lang="ts"> <script lang="ts">
import * as Button from '$lib/components/ui/button' import * as Button from "$lib/components/ui/button/index.js";
type $$Props = Button.Props
type $$Events = Button.Events type $$Props = Button.Props;
type $$Events = Button.Events;
</script> </script>
<Button.Root type="submit" {...$$restProps} on:click on:keydown> <Button.Root type="submit" on:click on:keydown {...$$restProps}>
<slot /> <slot />
</Button.Root> </Button.Root>

@ -1,25 +0,0 @@
<script lang="ts">
import { getFormField } from 'formsnap'
import type { Checkbox as CheckboxPrimitive } from 'bits-ui'
import { Checkbox } from '$lib/components/ui/checkbox'
type $$Props = CheckboxPrimitive.Props
type $$Events = CheckboxPrimitive.Events
export let onCheckedChange: $$Props['onCheckedChange'] = undefined
const { name, setValue, attrStore, value } = getFormField()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { name: nameAttr, value: valueAttr, ...rest } = $attrStore
</script>
<Checkbox
{...rest}
checked={typeof $value === 'boolean' ? $value : false}
onCheckedChange={(v) => {
onCheckedChange?.(v)
setValue(v)
}}
{...$$restProps}
on:click
on:keydown />
<input hidden {name} value={$value} />

@ -1,15 +1,17 @@
<script lang="ts"> <script lang="ts">
import { Form as FormPrimitive } from 'formsnap' import * as FormPrimitive from "formsnap";
import { cn } from '$lib/utils' import type { HTMLAttributes } from "svelte/elements";
import type { HTMLAttributes } from 'svelte/elements' import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLSpanElement> type $$Props = HTMLAttributes<HTMLSpanElement>;
let className: string | undefined | null = undefined let className: string | undefined | null = undefined;
export { className as class } export { className as class };
</script> </script>
<FormPrimitive.Description <FormPrimitive.Description
class={cn('text-sm text-muted-foreground', className)} class={cn("text-sm text-muted-foreground", className)}
{...$$restProps}> {...$$restProps}
<slot /> let:descriptionAttrs
>
<slot {descriptionAttrs} />
</FormPrimitive.Description> </FormPrimitive.Description>

@ -0,0 +1,25 @@
<script lang="ts" context="module">
import type { FormPathLeaves, SuperForm } from "sveltekit-superforms";
type T = Record<string, unknown>;
type U = FormPathLeaves<T>;
</script>
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPathLeaves<T>">
import type { HTMLAttributes } from "svelte/elements";
import * as FormPrimitive from "formsnap";
import { cn } from "$lib/utils.js";
type $$Props = FormPrimitive.ElementFieldProps<T, U> & HTMLAttributes<HTMLElement>;
export let form: SuperForm<T>;
export let name: U;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<FormPrimitive.ElementField {form} {name} let:constraints let:errors let:tainted let:value>
<div class={cn("space-y-2", className)}>
<slot {constraints} {errors} {tainted} {value} />
</div>
</FormPrimitive.ElementField>

@ -0,0 +1,26 @@
<script lang="ts">
import * as FormPrimitive from "formsnap";
import { cn } from "$lib/utils.js";
type $$Props = FormPrimitive.FieldErrorsProps & {
errorClasses?: string | undefined | null;
};
let className: $$Props["class"] = undefined;
export { className as class };
export let errorClasses: $$Props["class"] = undefined;
</script>
<FormPrimitive.FieldErrors
class={cn("text-sm font-medium text-destructive", className)}
{...$$restProps}
let:errors
let:fieldErrorsAttrs
let:errorAttrs
>
<slot {errors} {fieldErrorsAttrs} {errorAttrs}>
{#each errors as error}
<div {...errorAttrs} class={cn(errorClasses)}>{error}</div>
{/each}
</slot>
</FormPrimitive.FieldErrors>

@ -0,0 +1,25 @@
<script lang="ts" context="module">
import type { FormPath, SuperForm } from "sveltekit-superforms";
type T = Record<string, unknown>;
type U = FormPath<T>;
</script>
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
import type { HTMLAttributes } from "svelte/elements";
import * as FormPrimitive from "formsnap";
import { cn } from "$lib/utils.js";
type $$Props = FormPrimitive.FieldProps<T, U> & HTMLAttributes<HTMLElement>;
export let form: SuperForm<T>;
export let name: U;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<FormPrimitive.Field {form} {name} let:constraints let:errors let:tainted let:value>
<div class={cn("space-y-2", className)}>
<slot {constraints} {errors} {tainted} {value} />
</div>
</FormPrimitive.Field>

@ -0,0 +1,30 @@
<script lang="ts" context="module">
import type { FormPath, SuperForm } from "sveltekit-superforms";
type T = Record<string, unknown>;
type U = FormPath<T>;
</script>
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
import * as FormPrimitive from "formsnap";
import { cn } from "$lib/utils.js";
type $$Props = FormPrimitive.FieldsetProps<T, U>;
export let form: SuperForm<T>;
export let name: U;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<FormPrimitive.Fieldset
{form}
{name}
let:constraints
let:errors
let:tainted
let:value
class={cn("space-y-2", className)}
>
<slot {constraints} {errors} {tainted} {value} />
</FormPrimitive.Fieldset>

@ -1,27 +0,0 @@
<script lang="ts">
import { getFormField } from 'formsnap'
import type { HTMLInputAttributes } from 'svelte/elements'
import { Input, type InputEvents } from '$lib/components/ui/input'
type $$Props = HTMLInputAttributes
type $$Events = InputEvents
const { attrStore, value } = getFormField()
</script>
<Input
{...$attrStore}
bind:value={$value}
{...$$restProps}
on:blur
on:change
on:click
on:focus
on:keydown
on:keypress
on:keyup
on:mouseover
on:mouseenter
on:mouseleave
on:paste
on:input />

@ -1,12 +0,0 @@
<script lang="ts">
import { cn } from '$lib/utils'
import type { HTMLAttributes } from 'svelte/elements'
type $$Props = HTMLAttributes<HTMLDivElement>
let className: string | undefined | null = undefined
export { className as class }
</script>
<div class={cn('space-y-2', className)} {...$$restProps}>
<slot />
</div>

@ -1,20 +1,17 @@
<script lang="ts"> <script lang="ts">
import type { Label as LabelPrimitive } from 'bits-ui' import type { Label as LabelPrimitive } from "bits-ui";
import { getFormField } from 'formsnap' import { getFormControl } from "formsnap";
import { cn } from '$lib/utils' import { cn } from "$lib/utils.js";
import { Label } from '$lib/components/ui/label' import { Label } from "$lib/components/ui/label/index.js";
type $$Props = LabelPrimitive.Props type $$Props = LabelPrimitive.Props;
let className: $$Props['class'] = undefined let className: $$Props["class"] = undefined;
export { className as class } export { className as class };
const { errors, ids } = getFormField() const { labelAttrs } = getFormControl();
</script> </script>
<Label <Label {...$labelAttrs} class={cn("data-[fs-error]:text-destructive", className)} {...$$restProps}>
for={$ids.input} <slot {labelAttrs} />
class={cn($errors && 'text-destructive', className)}
{...$$restProps}>
<slot />
</Label> </Label>

@ -0,0 +1,17 @@
<script lang="ts">
import * as FormPrimitive from "formsnap";
import { cn } from "$lib/utils.js";
type $$Props = FormPrimitive.LegendProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<FormPrimitive.Legend
{...$$restProps}
class={cn("text-sm font-medium leading-none data-[fs-error]:text-destructive", className)}
let:legendAttrs
>
<slot {legendAttrs} />
</FormPrimitive.Legend>

@ -1,23 +0,0 @@
<script lang="ts">
import { Form as FormPrimitive } from 'formsnap'
import { buttonVariants } from '$lib/components/ui/button'
import { cn } from '$lib/utils'
import { ChevronDown } from 'lucide-svelte'
import type { HTMLSelectAttributes } from 'svelte/elements'
type $$Props = HTMLSelectAttributes
let className: string | undefined | null = undefined
export { className as class }
</script>
<FormPrimitive.Select
class={cn(
buttonVariants({ variant: 'outline' }),
'appearance-none bg-transparent font-normal',
className,
)}
{...$$restProps}>
<slot />
</FormPrimitive.Select>
<ChevronDown class="absolute right-3 top-2.5 h-4 w-4 opacity-50" />

@ -1,21 +0,0 @@
<script lang="ts">
import { getFormField } from 'formsnap'
import type { RadioGroup as RadioGroupPrimitive } from 'bits-ui'
import * as RadioGroup from '$lib/components/ui/radio-group'
type $$Props = RadioGroupPrimitive.Props
const { attrStore, setValue, name, value } = getFormField()
export let onValueChange: $$Props['onValueChange'] = undefined
</script>
<RadioGroup.Root
{...$attrStore}
onValueChange={(v) => {
onValueChange?.(v)
setValue(v)
}}
{...$$restProps}>
<slot />
<input hidden {name} value={$value} />
</RadioGroup.Root>

@ -1,17 +0,0 @@
<script lang="ts">
import * as Select from '$lib/components/ui/select'
import type { Select as SelectPrimitive } from 'bits-ui'
import { getFormField } from 'formsnap'
type $$Props = SelectPrimitive.TriggerProps & {
placeholder?: string
}
type $$Events = SelectPrimitive.TriggerEvents
const { attrStore } = getFormField()
export let placeholder = ''
</script>
<Select.Trigger {...$$restProps} {...$attrStore} on:click on:keydown>
<Select.Value {placeholder} />
<slot />
</Select.Trigger>

@ -1,19 +0,0 @@
<script lang="ts">
import * as Select from '$lib/components/ui/select'
import { getFormField } from 'formsnap'
import type { Select as SelectPrimitive } from 'bits-ui'
type $$Props = SelectPrimitive.Props
const { setValue, name, value } = getFormField()
export let onSelectedChange: $$Props['onSelectedChange'] = undefined
</script>
<Select.Root
onSelectedChange={(v) => {
onSelectedChange?.(v)
setValue(v ? v.value : undefined)
}}
{...$$restProps}>
<slot />
<input hidden {name} value={$value} />
</Select.Root>

@ -1,23 +0,0 @@
<script lang="ts">
import { getFormField } from 'formsnap'
import type { Switch as SwitchPrimitive } from 'bits-ui'
import { Switch } from '$lib/components/ui/switch'
type $$Props = SwitchPrimitive.Props
type $$Events = SwitchPrimitive.Events
export let onCheckedChange: $$Props['onCheckedChange'] = undefined
const { name, setValue, attrStore, value } = getFormField()
</script>
<Switch
{...$attrStore}
checked={typeof $value === 'boolean' ? $value : false}
onCheckedChange={(v) => {
onCheckedChange?.(v)
setValue(v)
}}
{...$$restProps}
on:click
on:keydown />
<input hidden {name} value={$value} />

@ -1,31 +0,0 @@
<script lang="ts">
import { getFormField } from 'formsnap'
import type { HTMLTextareaAttributes } from 'svelte/elements'
import type { TextareaGetFormField } from '.'
import {
Textarea,
type TextareaEvents,
} from '$lib/components/ui/textarea'
type $$Props = HTMLTextareaAttributes
type $$Events = TextareaEvents
const { attrStore, value } = getFormField() as TextareaGetFormField
</script>
<Textarea
{...$attrStore}
bind:value={$value}
{...$$restProps}
on:blur
on:change
on:click
on:focus
on:keydown
on:keypress
on:keyup
on:mouseover
on:mouseenter
on:mouseleave
on:paste
on:input />

@ -1,13 +0,0 @@
<script lang="ts">
import { Form as FormPrimitive } from 'formsnap'
import { cn } from '$lib/utils'
import type { HTMLAttributes } from 'svelte/elements'
type $$Props = HTMLAttributes<HTMLParagraphElement>
let className: string | undefined | null = undefined
export { className as class }
</script>
<FormPrimitive.Validation
class={cn('text-sm font-medium text-destructive', className)}
{...$$restProps} />

@ -1,85 +1,33 @@
import { Form as FormPrimitive, getFormField } from 'formsnap' import * as FormPrimitive from "formsnap";
import * as RadioGroupComp from '$lib/components/ui/radio-group' import Description from "./form-description.svelte";
import * as SelectComp from '$lib/components/ui/select' import Label from "./form-label.svelte";
import type { Writable } from 'svelte/store' import FieldErrors from "./form-field-errors.svelte";
import Item from './form-item.svelte' import Field from "./form-field.svelte";
import Input from './form-input.svelte' import Fieldset from "./form-fieldset.svelte";
import Textarea from './form-textarea.svelte' import Legend from "./form-legend.svelte";
import Description from './form-description.svelte' import ElementField from "./form-element-field.svelte";
import Label from './form-label.svelte' import Button from "./form-button.svelte";
import Validation from './form-validation.svelte'
import Checkbox from './form-checkbox.svelte'
import Switch from './form-switch.svelte'
import NativeSelect from './form-native-select.svelte'
import RadioGroup from './form-radio-group.svelte'
import Select from './form-select.svelte'
import SelectTrigger from './form-select-trigger.svelte'
import Button from './form-button.svelte'
const Root = FormPrimitive.Root const Control = FormPrimitive.Control;
const Field = FormPrimitive.Field
const Control = FormPrimitive.Control
const RadioItem = RadioGroupComp.Item
const NativeRadio = FormPrimitive.Radio
const SelectContent = SelectComp.Content
const SelectLabel = SelectComp.Label
const SelectGroup = SelectComp.Group
const SelectItem = SelectComp.Item
const SelectSeparator = SelectComp.Separator
export type TextareaGetFormField = Omit<
ReturnType<typeof getFormField>,
'value'
> & {
value: Writable<string>
}
export { export {
Root,
Field, Field,
Control, Control,
Item,
Input,
Label, Label,
Button, Button,
Switch, FieldErrors,
Select,
Checkbox,
Textarea,
Validation,
RadioGroup,
RadioItem,
Description, Description,
SelectContent, Fieldset,
SelectLabel, Legend,
SelectGroup, ElementField,
SelectItem,
SelectSeparator,
SelectTrigger,
NativeSelect,
NativeRadio,
// //
Root as Form,
Field as FormField, Field as FormField,
Control as FormControl, Control as FormControl,
Item as FormItem,
Input as FormInput,
Textarea as FormTextarea,
Description as FormDescription, Description as FormDescription,
Label as FormLabel, Label as FormLabel,
Validation as FormValidation, FieldErrors as FormFieldErrors,
NativeSelect as FormNativeSelect, Fieldset as FormFieldset,
NativeRadio as FormNativeRadio, Legend as FormLegend,
Checkbox as FormCheckbox, ElementField as FormElementField,
Switch as FormSwitch,
RadioGroup as FormRadioGroup,
RadioItem as FormRadioItem,
Select as FormSelect,
SelectContent as FormSelectContent,
SelectLabel as FormSelectLabel,
SelectGroup as FormSelectGroup,
SelectItem as FormSelectItem,
SelectSeparator as FormSelectSeparator,
SelectTrigger as FormSelectTrigger,
Button as FormButton, Button as FormButton,
} };

@ -1,6 +1,7 @@
<script> <script>
import { onMount } from 'svelte' import { onMount } from 'svelte'
import QRCode from 'qrcode' import QRCode from 'qrcode'
import { browser } from '$app/environment'
export let background = '#fff' export let background = '#fff'
export let color = '#000' export let color = '#000'
@ -28,6 +29,8 @@
} }
} }
$: browser && background && color && generateQrCode()
onMount(() => { onMount(() => {
generateQrCode() generateQrCode()
}) })

@ -0,0 +1,56 @@
<script lang="ts">
import * as Form from '$lib/components/ui/form'
import { Input } from '$lib/components/ui/input'
import { formSchema, type FormSchema } from '../schema'
import {
type SuperValidated,
type Infer,
superForm,
} from 'sveltekit-superforms'
import { zodClient } from 'sveltekit-superforms/adapters'
import SuperDebug from 'sveltekit-superforms'
import { toast } from 'svelte-sonner'
import DemoQr from './DemoQR.svelte'
export let data: SuperValidated<Infer<FormSchema>>
const form = superForm(data, {
validators: zodClient(formSchema),
resetForm: true,
onResult: ({ result }) => {
if (result.status === 200) {
toast.success('QR settings updated')
}
if (result.status === 400) {
toast.error('Error updating QR settings')
}
},
})
const { form: formData, enhance } = form
</script>
<DemoQr
background={$formData.qr_background}
color={$formData.qr_foreground} />
<form method="POST" use:enhance class="flex flex-col gap-6">
<Form.Field {form} name="qr_background" class="flex flex-col gap-2">
<Form.Control let:attrs>
<Form.Label>Background Color</Form.Label>
<Input {...attrs} bind:value={$formData.qr_background} />
</Form.Control>
<Form.Description>QR Code background color</Form.Description>
<Form.FieldErrors />
</Form.Field>
<Form.Field {form} name="qr_foreground" class="flex flex-col gap-2">
<Form.Control let:attrs>
<Form.Label>Foreground Color</Form.Label>
<Input {...attrs} bind:value={$formData.qr_foreground} />
</Form.Control>
<Form.Description>QR Code foreground color</Form.Description>
<Form.FieldErrors />
</Form.Field>
<Form.Button class="w-fit">Save</Form.Button>
</form>
<SuperDebug data={formData} />

@ -1,10 +1,53 @@
import { db } from '$lib/db' import { db } from '$lib/db'
import type { PageServerLoad } from './$types' import type { PageServerLoad, Actions } from './$types'
import { fail } from '@sveltejs/kit'
import { superValidate } from 'sveltekit-superforms'
import { formSchema } from './schema'
import { zod } from 'sveltekit-superforms/adapters'
import { setting } from '$lib/db/schema'
import { eq } from 'drizzle-orm'
export const load = (async (event) => { export const load = (async (event) => {
const settings = await db.query.setting.findFirst({ const settings = await db.query.setting.findFirst({
where: (setting, { eq }) => where: (setting, { eq }) =>
eq(setting.userId, event.locals.user.id), eq(setting.userId, event.locals.user.id),
}) })
return { settings }
const qr_background = settings?.qr_background || '#000'
const qr_foreground = settings?.qr_foreground || '#fff'
return {
settings,
form: await superValidate(
{ qr_background, qr_foreground },
zod(formSchema),
),
}
}) satisfies PageServerLoad }) satisfies PageServerLoad
export const actions: Actions = {
default: async (event) => {
const form = await superValidate(event, zod(formSchema))
if (!form.valid) {
return fail(400, {
form,
})
}
const userId = event.locals.user.id
const settings = await db.query.setting.findFirst({
where: (settingData, { eq }) => eq(settingData.userId, userId),
})
if (!settings) {
await db.insert(setting).values({ userId })
}
await db
.update(setting)
.set(form.data)
.where(eq(setting.userId, userId))
return {
form,
}
},
}

@ -1,85 +1,19 @@
<script lang="ts"> <script lang="ts">
import { Separator } from '$lib/components/ui/separator' import { Separator } from '$lib/components/ui/separator'
import { Input } from '$lib/components/ui/input'
import { Label } from '$lib/components/ui/label'
import type { PageData } from './$types' import type { PageData } from './$types'
import Button from '$lib/components/ui/button/button.svelte' import Form from './(components)/form.svelte'
import { Loader2 } from 'lucide-svelte'
import { invalidateAll } from '$app/navigation'
import { toast } from 'svelte-sonner'
import DemoQr from './(components)/DemoQR.svelte'
export let data: PageData export let data: PageData
let isLoading = false
let qr_data = {
background_color: data.settings?.qr_background || '#fff',
foreground_color: data.settings?.qr_foreground || '#000',
}
const submit = async () => {
isLoading = true
try {
const response = await fetch('/api/account/qr', {
method: 'PUT',
body: JSON.stringify({
qr_background: qr_data.background_color,
qr_foreground: qr_data.foreground_color,
}),
})
const body = await response.json()
if (body.success) {
toast.success('QR Details Updated')
await invalidateAll()
}
} catch (error) {
toast.error('Error Occurred')
} finally {
isLoading = false
}
}
</script> </script>
<div class="space-y-6"> <div class="space-y-6">
<div> <div>
<h3 class="text-lg font-medium">Account</h3> <h3 class="text-lg font-medium">QR</h3>
<p class="text-muted-foreground text-sm"> <p class="text-sm text-muted-foreground">
Update your account settings. Update your QR settings.
</p> </p>
</div> </div>
<Separator /> <Separator />
{#key qr_data} <Form data={data.form} />
<DemoQr
background={qr_data.background_color}
color={qr_data.foreground_color} />
{/key}
<div class="flex w-full max-w-sm flex-col gap-2">
<Label for="background_color">Background Color</Label>
<Input
type="text"
id="background_color"
placeholder="#ffffff"
bind:value={qr_data.background_color} />
</div>
<div class="flex w-full max-w-sm flex-col gap-2">
<Label for="foreground_color">Foreground Color</Label>
<Input
type="text"
id="foreground_color"
placeholder="#000000"
bind:value={qr_data.foreground_color} />
</div>
<Button disabled={isLoading} on:click={submit} class="flex gap-2">
{#if isLoading}
<Loader2 class="animate-spin" />
{/if}
Save</Button>
</div> </div>

@ -0,0 +1,14 @@
import { z } from 'zod'
export const formSchema = z.object({
qr_background: z
.string()
.min(1, { message: 'Background color is required' })
.max(7),
qr_foreground: z
.string()
.min(1, { message: 'Foreground color is required' })
.max(7),
})
export type FormSchema = typeof formSchema

@ -1,32 +0,0 @@
import { db } from '$lib/db'
import { setting } from '$lib/db/schema'
import { qrUpdateSchema } from '$lib/server/types'
import { eq } from 'drizzle-orm'
import type { RequestHandler } from './$types'
export const PUT: RequestHandler = async (event) => {
const body = await event.request.json()
const qrUpdate = qrUpdateSchema.safeParse(body)
const userId = event.locals.user.id
if (!qrUpdate.success) {
return new Response(JSON.stringify({ success: false }))
}
try {
const settings = await db.query.setting.findFirst({
where: (settingData, { eq }) => eq(settingData.userId, userId),
})
if (!settings) {
await db.insert(setting).values({ userId })
}
await db
.update(setting)
.set(qrUpdate.data)
.where(eq(setting.userId, userId))
return new Response(JSON.stringify({ success: true }))
} catch (error) {
return new Response(JSON.stringify({ success: false }))
}
}
Loading…
Cancel
Save