From 297202b6cbf0b3920e4f1cb5350f8d2ba9c5d998 Mon Sep 17 00:00:00 2001 From: glitchingcore <102431570+glitchingcore@users.noreply.github.com> Date: Sat, 19 Oct 2024 12:58:33 +0200 Subject: [PATCH] Implement Links and Skills order modification via Drag and Drop Added '/profile/links/order' and '/profile/skills/order' endpoints. --- prisma/schema.prisma | 2 ++ src/lib/components/MyProfile/LinkForm.svelte | 9 ++++++ .../components/MyProfile/SkillsForm.svelte | 8 +++++ src/lib/components/MyProfile/UserLinks.svelte | 22 ++++++++++--- .../components/MyProfile/UserSkills.svelte | 32 +++++++++++++++---- src/lib/schemas/links.ts | 3 +- src/lib/schemas/skills.ts | 3 +- src/routes/profile/+page.server.ts | 16 ++++++---- src/routes/profile/+page.svelte | 4 +-- src/routes/profile/links/order/+server.ts | 21 ++++++++++++ src/routes/profile/skills/order/+server.ts | 21 ++++++++++++ 11 files changed, 121 insertions(+), 20 deletions(-) create mode 100644 src/routes/profile/links/order/+server.ts create mode 100644 src/routes/profile/skills/order/+server.ts diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 8699705..4acf6fb 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -30,6 +30,7 @@ model Link { url String postedBy User @relation(fields: [userId], references: [githubId]) userId Int + order Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } @@ -40,6 +41,7 @@ model Skill { level String postedBy User @relation(fields: [userId], references: [githubId]) userId Int + order Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } diff --git a/src/lib/components/MyProfile/LinkForm.svelte b/src/lib/components/MyProfile/LinkForm.svelte index 415c1d5..4ad020c 100644 --- a/src/lib/components/MyProfile/LinkForm.svelte +++ b/src/lib/components/MyProfile/LinkForm.svelte @@ -6,12 +6,15 @@ import { zodClient } from 'sveltekit-superforms/adapters'; export let data: SuperValidated>; + export let linksLength: number; const form = superForm(data, { validators: zodClient(linksSchema) }); const { form: formData, enhance } = form; + + $: $formData.order = linksLength;
+ + + + + + Add
diff --git a/src/lib/components/MyProfile/SkillsForm.svelte b/src/lib/components/MyProfile/SkillsForm.svelte index a4be126..20d1ce8 100644 --- a/src/lib/components/MyProfile/SkillsForm.svelte +++ b/src/lib/components/MyProfile/SkillsForm.svelte @@ -7,6 +7,7 @@ import { zodClient } from 'sveltekit-superforms/adapters'; export let data: SuperValidated>; + export let skillsLength: number; const form = superForm(data, { validators: zodClient(skillsSchema), @@ -21,6 +22,7 @@ const { form: formData, enhance } = form; + $: $formData.order = skillsLength; $: selectedLevel = $formData.level ? { label: $formData.level, @@ -73,5 +75,11 @@ + + + + + + Add diff --git a/src/lib/components/MyProfile/UserLinks.svelte b/src/lib/components/MyProfile/UserLinks.svelte index 62c2a7c..bbc5010 100644 --- a/src/lib/components/MyProfile/UserLinks.svelte +++ b/src/lib/components/MyProfile/UserLinks.svelte @@ -7,8 +7,22 @@ import { Trash2, Copy } from 'lucide-svelte'; import { copyToClipboard } from '$lib/utils/copyToClipboard'; import { confirmDelete } from '$lib/utils/confirmDelete'; + import DnD from '$lib/components/Shared/DnD.svelte'; + import type { Link } from '@prisma/client'; - export let links; // Use the Link type for the links prop + export let links: Link[]; // Use the Link type for the links prop + let dragDisabled = false; + async function handleDrop() { + dragDisabled = true; + await fetch('/profile/links/order', { + method: 'PATCH', + body: JSON.stringify({ links }), + headers: { + 'content-type': 'application/json', + }, + }); + dragDisabled = false; + } @@ -26,8 +40,8 @@ Actions - - {#each links as link} + links = newLinks} containerTag="tbody" class="[&_tr:last-child]:border-0" onDrop={handleDrop}> + {#each links as link(link.id)}
{link.title}
@@ -56,7 +70,7 @@
{/each} -
+
diff --git a/src/lib/components/MyProfile/UserSkills.svelte b/src/lib/components/MyProfile/UserSkills.svelte index 92fd7a4..9c6c86d 100644 --- a/src/lib/components/MyProfile/UserSkills.svelte +++ b/src/lib/components/MyProfile/UserSkills.svelte @@ -1,16 +1,36 @@ -
- {#each skills as skill} + (skills = newSkills)} + class="grid gap-4" + onDrop={handleDrop} +> + {#each skills as skill(skill.id)}
@@ -28,4 +48,4 @@
{/each} -
+ diff --git a/src/lib/schemas/links.ts b/src/lib/schemas/links.ts index 578cb55..099663a 100644 --- a/src/lib/schemas/links.ts +++ b/src/lib/schemas/links.ts @@ -8,7 +8,8 @@ export const linksSchema = z.object({ .max(200) .refine((val) => val.startsWith('http://') || val.startsWith('https://'), { message: 'Oops! URLs usually start with http:// or https:// :P' - }) + }), + order: z.number() }); export type LinksSchema = typeof linksSchema; diff --git a/src/lib/schemas/skills.ts b/src/lib/schemas/skills.ts index e5b3230..bf32453 100644 --- a/src/lib/schemas/skills.ts +++ b/src/lib/schemas/skills.ts @@ -2,7 +2,8 @@ import { z } from 'zod'; export const skillsSchema = z.object({ title: z.string().min(1).max(50), - level: z.string() + level: z.string(), + order: z.number() }); export type SkillsSchema = typeof skillsSchema; diff --git a/src/routes/profile/+page.server.ts b/src/routes/profile/+page.server.ts index 0b6a223..9557183 100644 --- a/src/routes/profile/+page.server.ts +++ b/src/routes/profile/+page.server.ts @@ -45,11 +45,13 @@ export const load: PageServerLoad = async (event) => { // Fetch links and skills related to the user const links = await prisma.link.findMany({ - where: { userId: user.githubId } + where: { userId: user.githubId }, + orderBy: [{ order: 'asc' }] }); const skills = await prisma.skill.findMany({ - where: { userId: user.githubId } + where: { userId: user.githubId }, + orderBy: [{ order: 'asc' }] }); // Create userStats object @@ -83,7 +85,7 @@ export const actions: Actions = { } // If no errors, get data - const { title, url } = form.data; + const { title, url, order } = form.data; if (user) { try { @@ -91,7 +93,8 @@ export const actions: Actions = { data: { title, url, - userId: user.githubId + userId: user.githubId, + order } }); } catch (error) { @@ -137,7 +140,7 @@ export const actions: Actions = { } // If no errors, get data - const { title, level } = form.data; + const { title, level, order } = form.data; if (user) { try { @@ -145,7 +148,8 @@ export const actions: Actions = { data: { title, level, - userId: user.githubId + userId: user.githubId, + order } }); } catch (error) { diff --git a/src/routes/profile/+page.svelte b/src/routes/profile/+page.svelte index d5111ee..f3912ec 100644 --- a/src/routes/profile/+page.svelte +++ b/src/routes/profile/+page.svelte @@ -68,7 +68,7 @@
Links The links visible on your profile - +
@@ -79,7 +79,7 @@ Tech Stack - + diff --git a/src/routes/profile/links/order/+server.ts b/src/routes/profile/links/order/+server.ts new file mode 100644 index 0000000..3b83ce3 --- /dev/null +++ b/src/routes/profile/links/order/+server.ts @@ -0,0 +1,21 @@ +import type { RequestHandler } from './$types'; +import { prisma } from '$lib/server/prisma'; +import type { Link } from '@prisma/client/wasm'; + +export const PATCH: RequestHandler = async (event) => { + const json = await event.request.json(); + const links: Link[] = json.links; + + links.forEach(async (link, idx) => { + await prisma.link.update({ + where: { + id: link.id + }, + data: { + order: idx + } + }); + }); + + return new Response(); +}; diff --git a/src/routes/profile/skills/order/+server.ts b/src/routes/profile/skills/order/+server.ts new file mode 100644 index 0000000..93c94c4 --- /dev/null +++ b/src/routes/profile/skills/order/+server.ts @@ -0,0 +1,21 @@ +import type { RequestHandler } from './$types'; +import { prisma } from '$lib/server/prisma'; +import type { Skill } from '@prisma/client/wasm'; + +export const PATCH: RequestHandler = async (event) => { + const json = await event.request.json(); + const skills: Skill[] = json.skills; + + skills.forEach(async (skill, idx) => { + await prisma.skill.update({ + where: { + id: skill.id + }, + data: { + order: idx + } + }); + }); + + return new Response(); +};