Skip to content

Commit

Permalink
add support for profile pictures (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmintey authored Mar 6, 2023
1 parent fef1de3 commit 0a4a3af
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 14 deletions.
Binary file removed prisma/dev.db-journal
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "user" ADD COLUMN "picture" TEXT;
1 change: 1 addition & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ model User {
username String @unique
name String
email String @unique @default("[email protected]")
picture String?
items Item[] @relation("MyItems")
addedItems Item[] @relation("AddedItems")
plegedItems Item[] @relation("PledgedItems")
Expand Down
1 change: 1 addition & 0 deletions src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ declare global {
name: string;
email: string;
roleId: number;
picture?: string | null;
};
}

Expand Down
15 changes: 15 additions & 0 deletions src/lib/components/Avatar.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script lang="ts">
import { Avatar } from "@skeletonlabs/skeleton";
export let user: {
name: string;
picture?: string | null;
};
</script>

<Avatar
initials={user?.name.split(" ").reduce((x, y) => x + y.at(0), "")}
src={user?.picture ? `/api/assets/${user.picture}` : ""}
background={user?.picture ? "" : "bg-primary-400-500-token"}
{...$$props}
/>
7 changes: 2 additions & 5 deletions src/lib/components/UserCard.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { Avatar } from "@skeletonlabs/skeleton";
import Avatar from "./Avatar.svelte";
export let hideCount = false;
export let user: {
Expand All @@ -15,10 +15,7 @@
<a class="card" href="/wishlists/{user.username}" data-sveltekit-preload-data>
<div class="card-header">
<div class="flex flex-row space-x-4 items-center">
<Avatar
initials={user.name.split(" ").reduce((x, y) => x + y.at(0), "")}
background="bg-primary-400-500-token"
/>
<Avatar {user} />
<span class="font-bold text-3xl">
<span class="unstyled no-underline text-primary-700-200-token">{user.name}</span>
</span>
Expand Down
8 changes: 3 additions & 5 deletions src/lib/components/navigation/NavMenu.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<script lang="ts">
import { invalidateAll } from "$app/navigation";
import type { ClientUser } from "@lucia-auth/sveltekit/client";
import { Avatar, LightSwitch, popup, type PopupSettings } from "@skeletonlabs/skeleton";
import { LightSwitch, popup, type PopupSettings } from "@skeletonlabs/skeleton";
import type { Readable } from "svelte/store";
import Avatar from "../Avatar.svelte";
export let user: Readable<ClientUser>;
Expand All @@ -16,10 +17,7 @@
<div class="flex flex-row space-x-2 items-center">
<span class="relative">
<button use:popup={menuSettings}>
<Avatar
initials={$user.name.split(" ").reduce((x, y) => x + y.at(0), "")}
background="bg-primary-400-500-token"
/>
<Avatar user={$user} />
</button>
<nav class="list-nav card p-4 w-fit shadow-xl" data-popup="user">
<ul>
Expand Down
3 changes: 2 additions & 1 deletion src/lib/server/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export const auth = lucia({
username: userData.username,
email: userData.email,
name: userData.name,
roleId: userData.roleId
roleId: userData.roleId,
picture: userData.picture
};
}
});
Expand Down
2 changes: 2 additions & 0 deletions src/routes/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const load = (async ({ locals }) => {
select: {
name: true,
username: true,
picture: true,
items: {
select: {
id: true
Expand Down Expand Up @@ -47,6 +48,7 @@ export const load = (async ({ locals }) => {
select: {
username: true,
name: true,
picture: true,
items: {
select: {
id: true
Expand Down
34 changes: 34 additions & 0 deletions src/routes/account/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { client } from "$lib/server/prisma";
import { resetPasswordSchema } from "$lib/validations/resetPassword";
import type { PrismaClientKnownRequestError } from "@prisma/client/runtime";
import { fail, redirect } from "@sveltejs/kit";
import { writeFileSync } from "fs";
import { z } from "zod";
import type { Actions, PageServerLoad } from "./$types";

Expand Down Expand Up @@ -62,6 +63,39 @@ export const actions: Actions = {
}
},

profilePicture: async ({ request, locals }) => {
const { user, session } = await locals.validateUser();
if (!session) throw redirect(302, "/login?ref=/account");

const form = await request.formData();
const image = form.get("profilePic") as File;

let filename = null;

const create_image = image.size > 0 && image.size <= 5000000;

if (create_image) {
const ext = image.name.split(".").pop();
filename = user?.username + "-" + Date.now().toString() + "." + ext;

const ab = await image.arrayBuffer();

writeFileSync(`uploads/${filename}`, Buffer.from(ab));
console.log("wrote image");
}

if (filename) {
await client.user.update({
where: {
id: user.userId
},
data: {
picture: filename
}
});
}
},

passwordchange: async ({ request, locals }) => {
const { user, session } = await locals.validateUser();
if (!session) throw redirect(302, "/login?ref=/account");
Expand Down
43 changes: 40 additions & 3 deletions src/routes/account/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<script lang="ts">
import { enhance } from "$app/forms";
import ChangePassword from "$lib/components/account/ChangePassword.svelte";
import EditProfile from "$lib/components/account/EditProfile.svelte";
import { Avatar, Tab, TabGroup } from "@skeletonlabs/skeleton";
import Avatar from "$lib/components/Avatar.svelte";
import { FileButton, Tab, TabGroup } from "@skeletonlabs/skeleton";
import type { PageServerData } from "./$types";
export let data: PageServerData;
$: initials = data.user.name.split(" ").reduce((x, y) => x + y.at(0), "");
let submitButton: HTMLElement;
let tabSet = 0;
</script>

Expand All @@ -16,7 +19,21 @@
<svelte:fragment slot="panel">
{#if tabSet === 0}
<div class="flex flex-col w-fit items-center">
<Avatar width="w-24 md:w-32" {initials} background="bg-primary-400-500-token" />
<div class="picture">
<Avatar user={data.user} width="w-24 md:w-32" />
<form method="POST" class="add-icon" action="?/profilePicture" use:enhance>
<FileButton
name="profilePic"
id="profilePic"
accept="image/*"
button="btn-icon variant-glass-secondary"
on:change={() => submitButton.click()}
>
<iconify-icon icon="ion:camera" class="text-2xl" />
</FileButton>
<button type="submit" bind:this={submitButton} />
</form>
</div>

<EditProfile user={data.user} />
</div>
Expand All @@ -29,3 +46,23 @@
<svelte:head>
<title>Account</title>
</svelte:head>

<style>
.picture {
width: 100% !important;
height: 100% !important;
max-width: 150px !important;
max-height: 150px !important;
margin: auto;
position: relative;
}
.add-icon {
width: 50px;
height: 50px;
border-radius: 100%;
position: absolute;
bottom: 0;
right: 0;
}
</style>

0 comments on commit 0a4a3af

Please sign in to comment.