mirror of https://github.com/TZGyn/shortener
update qr settings page to use page action
parent
9024bd4f04
commit
79ec261c26
Binary file not shown.
@ -1,9 +1,10 @@
|
||||
<script lang="ts">
|
||||
import * as Button from '$lib/components/ui/button'
|
||||
type $$Props = Button.Props
|
||||
type $$Events = Button.Events
|
||||
import * as Button from "$lib/components/ui/button/index.js";
|
||||
|
||||
type $$Props = Button.Props;
|
||||
type $$Events = Button.Events;
|
||||
</script>
|
||||
|
||||
<Button.Root type="submit" {...$$restProps} on:click on:keydown>
|
||||
<Button.Root type="submit" on:click on:keydown {...$$restProps}>
|
||||
<slot />
|
||||
</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">
|
||||
import { Form as FormPrimitive } from 'formsnap'
|
||||
import { cn } from '$lib/utils'
|
||||
import type { HTMLAttributes } from 'svelte/elements'
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLSpanElement>
|
||||
let className: string | undefined | null = undefined
|
||||
export { className as class }
|
||||
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.Description
|
||||
class={cn('text-sm text-muted-foreground', className)}
|
||||
{...$$restProps}>
|
||||
<slot />
|
||||
class={cn("text-sm text-muted-foreground", className)}
|
||||
{...$$restProps}
|
||||
let:descriptionAttrs
|
||||
>
|
||||
<slot {descriptionAttrs} />
|
||||
</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">
|
||||
import type { Label as LabelPrimitive } from 'bits-ui'
|
||||
import { getFormField } from 'formsnap'
|
||||
import { cn } from '$lib/utils'
|
||||
import { Label } from '$lib/components/ui/label'
|
||||
import type { Label as LabelPrimitive } from "bits-ui";
|
||||
import { getFormControl } from "formsnap";
|
||||
import { cn } from "$lib/utils.js";
|
||||
import { Label } from "$lib/components/ui/label/index.js";
|
||||
|
||||
type $$Props = LabelPrimitive.Props
|
||||
type $$Props = LabelPrimitive.Props;
|
||||
|
||||
let className: $$Props['class'] = undefined
|
||||
export { className as class }
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
|
||||
const { errors, ids } = getFormField()
|
||||
const { labelAttrs } = getFormControl();
|
||||
</script>
|
||||
|
||||
<Label
|
||||
for={$ids.input}
|
||||
class={cn($errors && 'text-destructive', className)}
|
||||
{...$$restProps}>
|
||||
<slot />
|
||||
<Label {...$labelAttrs} class={cn("data-[fs-error]:text-destructive", className)} {...$$restProps}>
|
||||
<slot {labelAttrs} />
|
||||
</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 RadioGroupComp from '$lib/components/ui/radio-group'
|
||||
import * as SelectComp from '$lib/components/ui/select'
|
||||
import type { Writable } from 'svelte/store'
|
||||
import Item from './form-item.svelte'
|
||||
import Input from './form-input.svelte'
|
||||
import Textarea from './form-textarea.svelte'
|
||||
import Description from './form-description.svelte'
|
||||
import Label from './form-label.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'
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import Description from "./form-description.svelte";
|
||||
import Label from "./form-label.svelte";
|
||||
import FieldErrors from "./form-field-errors.svelte";
|
||||
import Field from "./form-field.svelte";
|
||||
import Fieldset from "./form-fieldset.svelte";
|
||||
import Legend from "./form-legend.svelte";
|
||||
import ElementField from "./form-element-field.svelte";
|
||||
import Button from "./form-button.svelte";
|
||||
|
||||
const Root = FormPrimitive.Root
|
||||
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>
|
||||
}
|
||||
const Control = FormPrimitive.Control;
|
||||
|
||||
export {
|
||||
Root,
|
||||
Field,
|
||||
Control,
|
||||
Item,
|
||||
Input,
|
||||
Label,
|
||||
Button,
|
||||
Switch,
|
||||
Select,
|
||||
Checkbox,
|
||||
Textarea,
|
||||
Validation,
|
||||
RadioGroup,
|
||||
RadioItem,
|
||||
FieldErrors,
|
||||
Description,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
NativeSelect,
|
||||
NativeRadio,
|
||||
Fieldset,
|
||||
Legend,
|
||||
ElementField,
|
||||
//
|
||||
Root as Form,
|
||||
Field as FormField,
|
||||
Control as FormControl,
|
||||
Item as FormItem,
|
||||
Input as FormInput,
|
||||
Textarea as FormTextarea,
|
||||
Description as FormDescription,
|
||||
Label as FormLabel,
|
||||
Validation as FormValidation,
|
||||
NativeSelect as FormNativeSelect,
|
||||
NativeRadio as FormNativeRadio,
|
||||
Checkbox as FormCheckbox,
|
||||
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,
|
||||
FieldErrors as FormFieldErrors,
|
||||
Fieldset as FormFieldset,
|
||||
Legend as FormLegend,
|
||||
ElementField as FormElementField,
|
||||
Button as FormButton,
|
||||
}
|
||||
};
|
||||
|
||||
@ -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 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) => {
|
||||
const settings = await db.query.setting.findFirst({
|
||||
where: (setting, { eq }) =>
|
||||
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
|
||||
|
||||
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">
|
||||
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 Button from '$lib/components/ui/button/button.svelte'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import { invalidateAll } from '$app/navigation'
|
||||
import { toast } from 'svelte-sonner'
|
||||
import DemoQr from './(components)/DemoQR.svelte'
|
||||
import Form from './(components)/form.svelte'
|
||||
|
||||
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>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<h3 class="text-lg font-medium">Account</h3>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
Update your account settings.
|
||||
<h3 class="text-lg font-medium">QR</h3>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Update your QR settings.
|
||||
</p>
|
||||
</div>
|
||||
<Separator />
|
||||
|
||||
{#key qr_data}
|
||||
<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>
|
||||
<Form data={data.form} />
|
||||
</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…
Reference in New Issue