From aa4a7cd2d33d13de7cbbc520437684da6d3db9cc Mon Sep 17 00:00:00 2001 From: glazk0 <43091603+glazk0@users.noreply.github.com> Date: Wed, 29 Jan 2025 12:29:45 +0100 Subject: [PATCH] feat: chat --- package.json | 6 +- pnpm-lock.yaml | 18 ++-- src/lib/components/app-sidebar.svelte | 7 ++ src/lib/components/ui/tabs/index.ts | 18 ++++ .../components/ui/tabs/tabs-content.svelte | 19 ++++ src/lib/components/ui/tabs/tabs-list.svelte | 19 ++++ .../components/ui/tabs/tabs-trigger.svelte | 19 ++++ .../(app)/admin/broadcast/+page.server.ts | 62 ++++++++++++ src/routes/(app)/admin/broadcast/+page.svelte | 97 +++++++++++++++++++ .../[chapterId]/groups/[name]/+page.svelte | 55 +++++++++++ src/routes/(auth)/register/+page.svelte | 28 +++--- 11 files changed, 320 insertions(+), 28 deletions(-) create mode 100644 src/lib/components/ui/tabs/index.ts create mode 100644 src/lib/components/ui/tabs/tabs-content.svelte create mode 100644 src/lib/components/ui/tabs/tabs-list.svelte create mode 100644 src/lib/components/ui/tabs/tabs-trigger.svelte create mode 100644 src/routes/(app)/admin/broadcast/+page.server.ts create mode 100644 src/routes/(app)/admin/broadcast/+page.svelte create mode 100644 src/routes/(app)/chapters/[chapterId]/groups/[name]/+page.svelte diff --git a/package.json b/package.json index 7a7143b..f17ef5d 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "@tailwindcss/forms": "^0.5.10", "@tailwindcss/typography": "^0.5.16", "autoprefixer": "^10.4.20", - "bits-ui": "1.0.0-next.78", + "bits-ui": "1.0.0-next.79", + "clsx": "^2.1.1", "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-svelte": "^2.46.1", @@ -38,6 +39,7 @@ "prettier-plugin-svelte": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.10", "svelte": "^5.0.0", + "svelte-boring-avatars": "^1.2.6", "svelte-check": "^4.0.0", "svelte-sonner": "^0.3.28", "sveltekit-superforms": "^2.23.1", @@ -49,8 +51,6 @@ "typescript-eslint": "^8.20.0", "vite": "^6.0.0", "vitest": "^3.0.0", - "svelte-boring-avatars": "^1.2.6", - "clsx": "^2.1.1", "zod": "^3.24.1" }, "dependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0fb2019..ecdbeda 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,8 +43,8 @@ importers: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.1) bits-ui: - specifier: 1.0.0-next.78 - version: 1.0.0-next.78(svelte@5.19.3) + specifier: 1.0.0-next.79 + version: 1.0.0-next.79(svelte@5.19.3) clsx: specifier: ^2.1.1 version: 2.1.1 @@ -813,8 +813,8 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} - bits-ui@1.0.0-next.78: - resolution: {integrity: sha512-jZjG2ObZ/CNyCNaXecpItC7hRXqJAgEfMhr06/eNrf3wHiiPyhdcy4OkzLcJyxeOrDyj+xma8cZTd3JRWqJdAw==} + bits-ui@1.0.0-next.79: + resolution: {integrity: sha512-k8cLe5LTTpssBJJ3VdRl9fHa9BFKZAe01xZ/jT3CZArgbq+XqOiQBvhPXwMYV/SKK3EvaOl7lxw13GI61tGxHA==} engines: {node: '>=18', pnpm: '>=8.7.0'} peerDependencies: svelte: ^5.11.0 @@ -1664,8 +1664,8 @@ packages: peerDependencies: svelte: ^5.7.0 - runed@0.22.0: - resolution: {integrity: sha512-ZWVXWhOr0P5xdNgtviz6D1ivLUDWKLCbeC5SUEJ3zBkqLReVqWHenFxMNFeFaiC5bfxhFxyxzyzB+98uYFtwdA==} + runed@0.23.1: + resolution: {integrity: sha512-h1ZDmin0LBoSMEZxvHOJbCWsUBz4099cjI+/rQ4FZystgOq294s5Rh+OEeu9HIObc8XQQEya23eAhJeal0VBuA==} peerDependencies: svelte: ^5.7.0 @@ -2709,13 +2709,13 @@ snapshots: binary-extensions@2.3.0: {} - bits-ui@1.0.0-next.78(svelte@5.19.3): + bits-ui@1.0.0-next.79(svelte@5.19.3): dependencies: '@floating-ui/core': 1.6.9 '@floating-ui/dom': 1.6.13 '@internationalized/date': 3.7.0 esm-env: 1.2.2 - runed: 0.22.0(svelte@5.19.3) + runed: 0.23.1(svelte@5.19.3) svelte: 5.19.3 svelte-toolbelt: 0.7.0(svelte@5.19.3) @@ -3489,7 +3489,7 @@ snapshots: esm-env: 1.2.2 svelte: 5.19.3 - runed@0.22.0(svelte@5.19.3): + runed@0.23.1(svelte@5.19.3): dependencies: esm-env: 1.2.2 svelte: 5.19.3 diff --git a/src/lib/components/app-sidebar.svelte b/src/lib/components/app-sidebar.svelte index b727d47..8fbf85f 100644 --- a/src/lib/components/app-sidebar.svelte +++ b/src/lib/components/app-sidebar.svelte @@ -6,6 +6,7 @@ import GitBranch from 'lucide-svelte/icons/git-branch'; import LayoutDashboard from 'lucide-svelte/icons/layout-dashboard'; import LogOut from 'lucide-svelte/icons/log-out'; + import Radio from 'lucide-svelte/icons/radio'; import ScrollText from 'lucide-svelte/icons/scroll-text'; import Settings from 'lucide-svelte/icons/settings'; @@ -61,6 +62,12 @@ url: '/admin/puzzles', icon: Code } + , + { + title: 'Broadcast', + url: '/admin/broadcast', + icon: Radio + } ] } ]); diff --git a/src/lib/components/ui/tabs/index.ts b/src/lib/components/ui/tabs/index.ts new file mode 100644 index 0000000..f1ab372 --- /dev/null +++ b/src/lib/components/ui/tabs/index.ts @@ -0,0 +1,18 @@ +import { Tabs as TabsPrimitive } from "bits-ui"; +import Content from "./tabs-content.svelte"; +import List from "./tabs-list.svelte"; +import Trigger from "./tabs-trigger.svelte"; + +const Root = TabsPrimitive.Root; + +export { + Root, + Content, + List, + Trigger, + // + Root as Tabs, + Content as TabsContent, + List as TabsList, + Trigger as TabsTrigger, +}; diff --git a/src/lib/components/ui/tabs/tabs-content.svelte b/src/lib/components/ui/tabs/tabs-content.svelte new file mode 100644 index 0000000..f1c0515 --- /dev/null +++ b/src/lib/components/ui/tabs/tabs-content.svelte @@ -0,0 +1,19 @@ + + + diff --git a/src/lib/components/ui/tabs/tabs-list.svelte b/src/lib/components/ui/tabs/tabs-list.svelte new file mode 100644 index 0000000..f03e5fc --- /dev/null +++ b/src/lib/components/ui/tabs/tabs-list.svelte @@ -0,0 +1,19 @@ + + + diff --git a/src/lib/components/ui/tabs/tabs-trigger.svelte b/src/lib/components/ui/tabs/tabs-trigger.svelte new file mode 100644 index 0000000..f1f5825 --- /dev/null +++ b/src/lib/components/ui/tabs/tabs-trigger.svelte @@ -0,0 +1,19 @@ + + + diff --git a/src/routes/(app)/admin/broadcast/+page.server.ts b/src/routes/(app)/admin/broadcast/+page.server.ts new file mode 100644 index 0000000..4eaa14c --- /dev/null +++ b/src/routes/(app)/admin/broadcast/+page.server.ts @@ -0,0 +1,62 @@ +import type { Actions, PageServerLoad } from "./$types"; + +import { API_URL } from "$env/static/private"; +import type { Chapter, Group } from "$lib/types"; +import { error, fail, redirect } from "@sveltejs/kit"; + +export const load: PageServerLoad = async ({ locals, fetch }) => { + if (!locals.user || !locals.user.email.endsWith('@peerat.dev')) { + redirect(302, '/'); + } + + let chapters: Chapter[] = []; + + let res = await fetch(API_URL + "/chapters"); + + if (res.ok) { + chapters = await res.json(); + } else { + console.error("Error fetching chapters"); + } + + const event = chapters?.filter((chapter) => chapter.start && chapter.end).pop(); + + if (!event) { + error(404); + } + + res = await fetch(`${API_URL}/groups/${event.id}`); + + if (!res.ok) redirect(302, "/chapters/" + event.id); + + const groups: Group[] = await res.json(); + + return { + title: "Broadcast" + " - " + event.name, + + event, + groups, + }; +}; + +export const actions: Actions = { + default: async ({ request, locals, fetch }) => { + if (!locals.user || !locals.user.email.endsWith('@peerat.dev')) { + return fail(401); + } + + const data = await request.formData(); + + const message = data.get('message') as string; + const group = data.get('group') as string; + + const body = group.length ? { group, message } : { message }; + + const res = await fetch(API_URL + "/admin/event/", { + method: "POST", + body: JSON.stringify(body), + }); + + console.log(res); + }, +}; diff --git a/src/routes/(app)/admin/broadcast/+page.svelte b/src/routes/(app)/admin/broadcast/+page.svelte new file mode 100644 index 0000000..22ad191 --- /dev/null +++ b/src/routes/(app)/admin/broadcast/+page.svelte @@ -0,0 +1,97 @@ + + +

Peer-at Broadcaster for {data.event.name}

+ +
+ + + {#if group} + {group} + {:else} + Global + {/if} + + + Global + {#each data.groups as group} + {group.name} + {/each} + + + + +
+ + + + + Global + {#each data.groups as group} + {group.name} + {/each} + + +
    + {#each messages['global'] as message} +
  • {message}
  • + {/each} +
+
+ {#each data.groups as group} + +
    + {#each messages[group.name] as message} +
  • {message}
  • + {/each} +
+
+ {/each} +
diff --git a/src/routes/(app)/chapters/[chapterId]/groups/[name]/+page.svelte b/src/routes/(app)/chapters/[chapterId]/groups/[name]/+page.svelte new file mode 100644 index 0000000..fe90504 --- /dev/null +++ b/src/routes/(app)/chapters/[chapterId]/groups/[name]/+page.svelte @@ -0,0 +1,55 @@ + + +
+
+
+

Peer-at Communication

+

+ Ici vous pouvez voir les messages envoyés par les administrateurs +

+
+
+
    + {#if broadcasts.length === 0} +
  • + Aucun message +
  • + {/if} + {#each broadcasts as broadcast, i (i)} +
  • + Message d'un peerat +

    {broadcast.message}

    +
  • + {/each} +
+
diff --git a/src/routes/(auth)/register/+page.svelte b/src/routes/(auth)/register/+page.svelte index 1c5c468..9c051d1 100644 --- a/src/routes/(auth)/register/+page.svelte +++ b/src/routes/(auth)/register/+page.svelte @@ -4,13 +4,13 @@ import { fade } from 'svelte/transition'; + import Loader from 'lucide-svelte/icons/loader-circle'; + import { toast } from 'svelte-sonner'; import { superForm } from 'sveltekit-superforms'; import { zodClient } from 'sveltekit-superforms/adapters'; - import Loader from 'lucide-svelte/icons/loader-circle'; import * as Form from '$lib/components/ui/form'; import { Input } from '$lib/components/ui/input'; - import * as InputOTP from '$lib/components/ui/input-otp'; import { formConfirmationSchema, formSchema } from './schema'; @@ -29,9 +29,9 @@ onResult: ({ result }) => { switch (result.type) { case 'success': - // toast.message('Demande de confirmation', { - // description: `Un code vous à été ${confirmation ? 'renvoyé' : 'envoyé'}.` - // }); + toast.message('Demande de confirmation', { + description: `Un code vous à été ${confirmation ? 'renvoyé' : 'envoyé'}.` + }); formConfirmationData.set({ ...$formData, passwd: '', @@ -48,10 +48,14 @@ const formConfirmation = superForm(data.formConfirmation, { validators: zodClient(formConfirmationSchema), - delayMs: 500, + delayMs: 500 }); - let { form: formConfirmationData, enhance: formConfirmationEnhance, delayed: formConfirmationDelayed } = formConfirmation; + let { + form: formConfirmationData, + enhance: formConfirmationEnhance, + delayed: formConfirmationDelayed + } = formConfirmation; {#if !confirmation} @@ -193,15 +197,7 @@ {#snippet children({ props })} Code de confirmation - - {#snippet children({ cells })} - - {#each cells as cell} - - {/each} - - {/snippet} - + {/snippet}