Skip to content

Commit

Permalink
Implement Links and Skills order modification via Drag and Drop
Browse files Browse the repository at this point in the history
Added '/profile/links/order' and '/profile/skills/order' endpoints.
  • Loading branch information
glitchingcore committed Oct 19, 2024
1 parent 32ba105 commit 297202b
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 20 deletions.
2 changes: 2 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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
}
9 changes: 9 additions & 0 deletions src/lib/components/MyProfile/LinkForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
import { zodClient } from 'sveltekit-superforms/adapters';
export let data: SuperValidated<Infer<LinksSchema>>;
export let linksLength: number;
const form = superForm(data, {
validators: zodClient(linksSchema)
});
const { form: formData, enhance } = form;
$: $formData.order = linksLength;
</script>

<form
Expand Down Expand Up @@ -40,5 +43,11 @@
</Form.Field>
</div>

<Form.Field {form} name="order">
<Form.Control let:attrs>
<Input {...attrs} bind:value={$formData.order} type="hidden" />
</Form.Control>
</Form.Field>

<Form.Button class="mt-5 flex align-bottom">Add</Form.Button>
</form>
8 changes: 8 additions & 0 deletions src/lib/components/MyProfile/SkillsForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { zodClient } from 'sveltekit-superforms/adapters';
export let data: SuperValidated<Infer<SkillsSchema>>;
export let skillsLength: number;
const form = superForm(data, {
validators: zodClient(skillsSchema),
Expand All @@ -21,6 +22,7 @@
const { form: formData, enhance } = form;
$: $formData.order = skillsLength;
$: selectedLevel = $formData.level
? {
label: $formData.level,
Expand Down Expand Up @@ -73,5 +75,11 @@
</Form.Field>
</div>

<Form.Field {form} name="order">
<Form.Control let:attrs>
<Input {...attrs} bind:value={$formData.order} type="hidden" />
</Form.Control>
</Form.Field>

<Form.Button>Add</Form.Button>
</form>
22 changes: 18 additions & 4 deletions src/lib/components/MyProfile/UserLinks.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
</script>

<Card.Root>
Expand All @@ -26,8 +40,8 @@
<Table.Head>Actions</Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
{#each links as link}
<DnD items={links} dndOptions={{ dragDisabled }} updateNewItems={(newLinks) => links = newLinks} containerTag="tbody" class="[&_tr:last-child]:border-0" onDrop={handleDrop}>
{#each links as link(link.id)}
<Table.Row>
<Table.Cell>
<div class="font-medium">{link.title}</div>
Expand Down Expand Up @@ -56,7 +70,7 @@
</Table.Cell>
</Table.Row>
{/each}
</Table.Body>
</DnD>
</Table.Root>
</Card.Content>
</Card.Root>
32 changes: 26 additions & 6 deletions src/lib/components/MyProfile/UserSkills.svelte
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
<script lang="ts">
import { BriefcaseBusiness, Trash2 } from 'lucide-svelte';
export let skills;
import { masteryLevels } from '$lib/constants/masteryLevel';
import { enhance } from '$app/forms';
import { Button } from '$lib/components/ui/button';
import { confirmDelete } from '$lib/utils/confirmDelete';
import DnD from '$lib/components/Shared/DnD.svelte';
import type { Skill } from '@prisma/client/wasm';
export let skills: Skill[];
let dragDisabled = false;
async function handleDrop() {
dragDisabled = true;
await fetch('/profile/skills/order', {
method: 'PATCH',
body: JSON.stringify({ skills }),
headers: {
'content-type': 'application/json'
}
});
dragDisabled = false;
}
</script>

<div class="grid gap-4">
{#each skills as skill}
<DnD
items={skills}
dndOptions={{ dragDisabled }}
updateNewItems={(newSkills) => (skills = newSkills)}
class="grid gap-4"
onDrop={handleDrop}
>
{#each skills as skill(skill.id)}
<div class="flex items-center gap-4">
<BriefcaseBusiness />
<div class="grid gap-1">
Expand All @@ -28,4 +48,4 @@
</div>
</div>
{/each}
</div>
</DnD>
3 changes: 2 additions & 1 deletion src/lib/schemas/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
3 changes: 2 additions & 1 deletion src/lib/schemas/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
16 changes: 10 additions & 6 deletions src/routes/profile/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -83,15 +85,16 @@ export const actions: Actions = {
}

// If no errors, get data
const { title, url } = form.data;
const { title, url, order } = form.data;

if (user) {
try {
await prisma.link.create({
data: {
title,
url,
userId: user.githubId
userId: user.githubId,
order
}
});
} catch (error) {
Expand Down Expand Up @@ -137,15 +140,16 @@ export const actions: Actions = {
}

// If no errors, get data
const { title, level } = form.data;
const { title, level, order } = form.data;

if (user) {
try {
await prisma.skill.create({
data: {
title,
level,
userId: user.githubId
userId: user.githubId,
order
}
});
} catch (error) {
Expand Down
4 changes: 2 additions & 2 deletions src/routes/profile/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
<div class="grid gap-2">
<Card.Title>Links</Card.Title>
<Card.Description>The links visible on your profile</Card.Description>
<LinkForm data={data.form} />
<LinkForm data={data.form} linksLength={data.links.length} />
</div>
</Card.Header>
<Card.Content>
Expand All @@ -79,7 +79,7 @@
<Card.Root>
<Card.Header>
<Card.Title>Tech Stack</Card.Title>
<SkillsForm data={data.skillsForm} />
<SkillsForm data={data.skillsForm} skillsLength={data.skills.length} />
</Card.Header>
<Card.Content class="grid gap-8">
<UserSkills skills={data.skills} />
Expand Down
21 changes: 21 additions & 0 deletions src/routes/profile/links/order/+server.ts
Original file line number Diff line number Diff line change
@@ -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();
};
21 changes: 21 additions & 0 deletions src/routes/profile/skills/order/+server.ts
Original file line number Diff line number Diff line change
@@ -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();
};

0 comments on commit 297202b

Please sign in to comment.