chore: no magic strings #34

Merged
BenjaminPalko merged 2 commits from paraglider-no-magic-strings into master 2024-12-30 17:29:47 -05:00
4 changed files with 54 additions and 28 deletions
Showing only changes of commit 904178629f - Show all commits

View file

@ -1,11 +1,17 @@
{ {
"$schema": "https://inlang.com/schema/inlang-message-format", "$schema": "https://inlang.com/schema/inlang-message-format",
"greeting": "Hello {name}!", "nav_greeting": "Hello {name}!",
"email_required": "Email is required", "login_tab_login": "Login",
"password_required": "Password is required", "login_tab_register": "Register",
"name_required": "Name is required", "login_label_email": "Email",
"email_incorrect": "Email is incorrect", "login_label_password": "Password",
"password_incorrect": "Password is incorrect", "login_label_name": "Name",
"email_inuse": "Email is already in use", "login_button_submit": "Submit",
"user_not_found": "The user could not be found" "login_error_email_required": "Email is required",
"login_error_password_required": "Password is required",
"login_error_name_required": "Name is required",
"login_error_email_incorrect": "Email is incorrect",
"login_error_password_incorrect": "Password is incorrect",
"login_error_email_inuse": "Email is already in use",
"login_error_user_not_found": "The user could not be found"
} }

View file

@ -3,7 +3,7 @@
let { title, username }: { title: string; username: string } = $props(); let { title, username }: { title: string; username: string } = $props();
let message = $derived(messages.greeting({ name: username })); let message = $derived(messages.nav_greeting({ name: username }));
</script> </script>
<header class="navbar justify-between bg-base-200 px-4"> <header class="navbar justify-between bg-base-200 px-4">

View file

@ -1,5 +1,4 @@
import { messages } from '$lib/i18n'; import { messages } from '$lib/i18n';
import { email_inuse } from '$lib/paraglide/messages';
import { logger } from '$lib/server/logger'; import { logger } from '$lib/server/logger';
import { auth } from '$lib/server/lucia.js'; import { auth } from '$lib/server/lucia.js';
import { prisma } from '$lib/server/prisma'; import { prisma } from '$lib/server/prisma';
@ -12,12 +11,12 @@ export const actions = {
const form = await event.request.formData(); const form = await event.request.formData();
const email = form.get('email'); const email = form.get('email');
if (typeof email !== 'string') { if (typeof email !== 'string') {
return fail(400, { email: { error: messages.email_required() } }); return fail(400, { email: { error: messages.login_error_email_required() } });
} }
const password = form.get('password') as string; const password = form.get('password') as string;
if (!password) { if (!password) {
return fail(400, { password: { error: messages.password_required() } }); return fail(400, { password: { error: messages.login_error_password_required() } });
} }
const user = await prisma.user.findUnique({ const user = await prisma.user.findUnique({
@ -27,13 +26,15 @@ export const actions = {
}); });
if (!user) { if (!user) {
logger.error(`User not found! ${email}`); logger.error(`User not found! ${email}`);
return fail(404, { email: { value: email, error: messages.user_not_found() } }); return fail(404, {
email: { value: email, error: messages.login_error_user_not_found() },
});
} }
const validPassword = await new Argon2id().verify(user.password, password); const validPassword = await new Argon2id().verify(user.password, password);
if (!validPassword) { if (!validPassword) {
return fail(400, { return fail(400, {
password: { error: messages.password_incorrect() }, password: { error: messages.login_error_password_incorrect() },
}); });
} }
const session = await auth.createSession(user.id, []); const session = await auth.createSession(user.id, []);
@ -48,26 +49,30 @@ export const actions = {
register: async (event) => { register: async (event) => {
const form = await event.request.formData(); const form = await event.request.formData();
if (!form.has('email')) { if (!form.has('email')) {
return fail(400, { email: { error: messages.email_required() } }); return fail(400, { email: { error: messages.login_error_email_required() } });
} }
const { success, data: email, error } = string().email().safeParse(form.get('email')); const { success, data: email, error } = string().email().safeParse(form.get('email'));
if (!success) { if (!success) {
logger.error(error); logger.error(error);
return fail(400, { email: { value: email, error: messages.email_incorrect() } }); return fail(400, {
email: { value: email, error: messages.login_error_email_incorrect() },
});
} }
const password = form.get('password'); const password = form.get('password');
if (typeof password !== 'string') { if (typeof password !== 'string') {
return fail(400, { password: { error: messages.password_required() } }); return fail(400, { password: { error: messages.login_error_password_required() } });
} }
const name = form.get('name'); const name = form.get('name');
if (typeof name !== 'string') { if (typeof name !== 'string') {
return fail(400, { name: { error: messages.name_required() } }); return fail(400, { name: { error: messages.login_error_name_required() } });
} }
const usersWithEmail = await prisma.user.count({ where: { email: email } }); const usersWithEmail = await prisma.user.count({ where: { email: email } });
if (usersWithEmail !== 0) { if (usersWithEmail !== 0) {
return fail(409, { email: { value: email, error: email_inuse() } }); return fail(409, {
email: { value: email, error: messages.login_error_email_inuse() },
});
} }
const hashedPassword = await new Argon2id().hash(password); const hashedPassword = await new Argon2id().hash(password);

View file

@ -2,6 +2,7 @@
import Button from '$lib/components/common/Button'; import Button from '$lib/components/common/Button';
import TextInput from '$lib/components/common/TextInput'; import TextInput from '$lib/components/common/TextInput';
import Tabs from '$lib/components/Navigation/Tabs'; import Tabs from '$lib/components/Navigation/Tabs';
import { messages } from '$lib/i18n/index.js';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
let { form } = $props(); let { form } = $props();
@ -31,19 +32,29 @@
{#snippet Form(variant: 'login' | 'register')} {#snippet Form(variant: 'login' | 'register')}
<form method="POST" action={`?/${variant}`}> <form method="POST" action={`?/${variant}`}>
<div class="card-body gap-4"> <div class="card-body gap-4">
<TextInput start={userIcon} placeholder="Email" name="email" type="email" /> <TextInput
start={userIcon}
placeholder={messages.login_label_email()}
name="email"
type="email"
/>
<TextInput <TextInput
start={passwordIcon} start={passwordIcon}
placeholder="Password" placeholder={messages.login_label_password()}
name="password" name="password"
type="password" type="password"
/> />
{#if variant === 'register'} {#if variant === 'register'}
<TextInput start={nameIcon} placeholder="Name" name="name" fade /> <TextInput
start={nameIcon}
placeholder={messages.login_label_name()}
name="name"
fade
/>
{/if} {/if}
</div> </div>
<div class="card-actions px-4"> <div class="card-actions px-4">
<Button block type="submit" label="Submit" outline /> <Button block type="submit" label={messages.login_button_submit()} outline />
</div> </div>
</form> </form>
{/snippet} {/snippet}
@ -54,7 +65,11 @@
{#if form} {#if form}
{@render alert(Object.values(form)[0].error)} {@render alert(Object.values(form)[0].error)}
{/if} {/if}
<Tabs variant="bordered" bind:selected={tab} tabs={['Login', 'Register']} /> <Tabs
variant="bordered"
bind:selected={tab}
tabs={[messages.login_tab_login(), messages.login_tab_register()]}
/>
</div> </div>
{@render Form(tab === 0 ? 'login' : 'register')} {@render Form(tab === 0 ? 'login' : 'register')}
</div> </div>