[portal][feat] add settings page

pull/527/head
Yangshun Tay 2 years ago
parent d1956ca12a
commit 57489d62e4

@ -44,7 +44,7 @@ function ProfileJewel() {
} }
const userNavigation = [ const userNavigation = [
// { href: '/profile', name: 'Profile' }, { href: '/settings', name: 'Settings' },
{ {
href: '/api/auth/signout', href: '/api/auth/signout',
name: 'Sign Out', name: 'Sign Out',

@ -0,0 +1,129 @@
import Head from 'next/head';
import type { Session } from 'next-auth';
import { useSession } from 'next-auth/react';
import { useState } from 'react';
import { Button, HorizontalDivider, TextInput, useToast } from '@tih/ui';
import Container from '~/components/shared/Container';
import { trpc } from '~/utils/trpc';
function SettingsForm({
session,
}: Readonly<{
session: Session;
}>) {
const { showToast } = useToast();
const updateProfileMutation = trpc.useMutation(
['user.settings.profile.update'],
{
onError: () => {
showToast({
subtitle: 'Please check that you are logged in.',
title: 'Failed to update profile',
variant: 'failure',
});
},
onSuccess: () => {
showToast({
title: 'Updated profile!',
variant: 'success',
});
},
},
);
const [name, setName] = useState(session?.user?.name);
return (
<div className="lg:py-18 bg-white py-12">
<Container variant="xs">
<div className="space-y-8">
<h1 className="text-4xl font-bold">Settings</h1>
<HorizontalDivider />
<p className="text-sm text-gray-500">
This information will be displayed publicly so be careful what you
share.
</p>
<form
className="space-y-8"
onSubmit={(event) => {
event.preventDefault();
updateProfileMutation.mutate({
name: name ? name : undefined,
});
}}>
<div className="grid grid-cols-1 gap-y-8 gap-x-4 sm:grid-cols-6">
<div className="sm:col-span-3">
<TextInput
description="This name will be used across the entire platform"
label="Name"
value={name ?? undefined}
onChange={(val) => setName(val)}
/>
</div>
{/* <div className="sm:col-span-6">
<label
className="block text-sm font-medium text-gray-700"
htmlFor="photo">
Profile Image
</label>
<div className="mt-1 flex items-center space-x-4">
{session?.user?.image ? (
<img
alt={session?.user?.email ?? session?.user?.name ?? ''}
className="h-16 w-16 rounded-full"
src={session?.user.image}
/>
) : (
<span className="h-16 w-16 overflow-hidden rounded-full bg-gray-100">
<svg
className="h-full w-full text-gray-300"
fill="currentColor"
viewBox="0 0 24 24">
<path d="M24 20.993V24H0v-2.996A14.977 14.977 0 0112.004 15c4.904 0 9.26 2.354 11.996 5.993zM16.002 8.999a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
</span>
)}
<Button label="Change" size="sm" variant="tertiary" />
</div>
</div> */}
</div>
<HorizontalDivider />
<div className="flex justify-end">
<Button
disabled={updateProfileMutation.isLoading}
isLoading={updateProfileMutation.isLoading}
label="Save"
type="submit"
variant="primary"
/>
</div>
</form>
</div>
</Container>
</div>
);
}
export default function SettingsPage() {
const { data: session, status } = useSession();
const isSessionLoading = status === 'loading';
if (isSessionLoading) {
return null;
}
if (session == null) {
return null;
}
return (
<>
<Head>
<title>Settings | Tech Interview Handbook</title>
</Head>
<SettingsForm session={session} />
</>
);
}

@ -29,6 +29,7 @@ import { resumesResumeUserRouter } from './resumes/resumes-resume-user-router';
import { resumesStarUserRouter } from './resumes/resumes-star-user-router'; import { resumesStarUserRouter } from './resumes/resumes-star-user-router';
import { todosRouter } from './todos'; import { todosRouter } from './todos';
import { todosUserRouter } from './todos-user-router'; import { todosUserRouter } from './todos-user-router';
import { userRouter } from './user-router';
export const appRouter = createRouter() export const appRouter = createRouter()
.transformer(superjson) .transformer(superjson)
@ -36,6 +37,7 @@ export const appRouter = createRouter()
// All keys should be delimited by a period and end with a period. // All keys should be delimited by a period and end with a period.
// Example routers. Learn more about tRPC routers: https://trpc.io/docs/v9/router // Example routers. Learn more about tRPC routers: https://trpc.io/docs/v9/router
.merge('auth.', protectedExampleRouter) .merge('auth.', protectedExampleRouter)
.merge('user.', userRouter)
.merge('todos.', todosRouter) .merge('todos.', todosRouter)
.merge('todos.user.', todosUserRouter) .merge('todos.user.', todosUserRouter)
.merge('companies.', companiesRouter) .merge('companies.', companiesRouter)

@ -0,0 +1,23 @@
import { z } from 'zod';
import { createProtectedRouter } from './context';
export const userRouter = createProtectedRouter().mutation(
'settings.profile.update',
{
input: z.object({
name: z.string().optional(),
}),
async resolve({ ctx, input }) {
const userId = ctx.session?.user?.id;
return await ctx.prisma.user.update({
data: {
name: input.name,
},
where: {
id: userId,
},
});
},
},
);
Loading…
Cancel
Save