public inbox for [email protected]
 help / color / mirror / Atom feed
From: Muhammad Rizki <[email protected]>
To: Ammar Faizi <[email protected]>
Cc: Kiizuha Kanazawa <[email protected]>,
	Alviro Iskandar Setiawan <[email protected]>,
	Dwiky Rizky Ananditya <[email protected]>,
	GNU/Weeb Mailing List <[email protected]>
Subject: [PATCH v1 14/16] feat(routes): add login page
Date: Sun, 19 Jan 2025 07:39:07 +0700	[thread overview]
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>

From: Kiizuha Kanazawa <[email protected]>

this page includes login form and its page authentication handler.

Signed-off-by: Kiizuha Kanazawa <[email protected]>
---
 src/routes/+page.svelte | 124 +++++++++++++++++++++++++++++++++++++++-
 src/routes/+page.ts     |  17 ++++++
 2 files changed, 139 insertions(+), 2 deletions(-)
 create mode 100644 src/routes/+page.ts

diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index cc88df0..46ef170 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -1,2 +1,122 @@
-<h1>Welcome to SvelteKit</h1>
-<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
+<script lang="ts">
+  import Loading from "$components/customs/loading.svelte";
+  import { Button } from "$components/ui/button";
+  import * as Card from "$components/ui/card";
+  import * as Form from "$components/ui/form";
+  import { Input } from "$components/ui/input";
+  import InputPassword from "$components/ui/input/input-password.svelte";
+  import { useAuth } from "$lib/hooks/auth.svelte";
+  import { useHttp } from "$lib/hooks/http.svelte";
+  import { loginSchema } from "$lib/schemas/login";
+  import type { LoginResponse, User } from "$typings";
+  import { superForm, setError, setMessage } from "sveltekit-superforms";
+  import { zod } from "sveltekit-superforms/adapters";
+
+  let { data } = $props();
+
+  const auth = useAuth();
+
+  const form = superForm(data.form, {
+    SPA: true,
+    validators: zod(loginSchema),
+
+    async onUpdate({ form }) {
+      const http = useHttp<LoginResponse, User>({
+        action: "login",
+        method: "POST",
+
+        payload: {
+          user: form.data.username_or_email,
+          pass: form.data.password
+        },
+
+        formatter(data, resp) {
+          data = resp?.data.res?.user_info!;
+        },
+
+        onComplete(resp) {
+          auth.save(resp.data.res!);
+        },
+
+        onError(_, errorMessage) {
+          setError(form, "username_or_email", "");
+          setError(form, "password", "");
+          setMessage(form, errorMessage);
+        }
+      });
+
+      await http.execute();
+    }
+  });
+
+  const isError = () => Boolean($errors.username_or_email && $errors.password);
+  const isValid = () => Boolean($formData.username_or_email && $formData.password);
+
+  const { form: formData, errors, message, submitting, constraints, enhance } = form;
+</script>
+
+<div class="mx-auto flex min-h-screen w-full items-center justify-center px-3 py-2">
+  <Card.Root class="w-full max-w-lg">
+    <form method="POST" use:enhance>
+      <Card.Header class="flex items-center justify-center space-y-1">
+        <Card.Title class="text-2xl">GNU/Weeb Mail Login</Card.Title>
+        <Card.Description>Proceed login to manager your email account</Card.Description>
+
+        {#if isError()}
+          <span class="text-sm font-medium text-destructive">
+            {$message}
+          </span>
+        {/if}
+      </Card.Header>
+
+      <Card.Content class="grid gap-4">
+        <Form.Field {form} name="username_or_email" class="grid gap-1">
+          <Form.Control>
+            {#snippet children({ props })}
+              <Form.Label>Username or Email</Form.Label>
+              <Input
+                {...props}
+                aria-invalid={$errors.username_or_email ? "true" : undefined}
+                bind:value={$formData.username_or_email}
+                placeholder="[email protected]"
+                disabled={$submitting}
+                {...$constraints.username_or_email}
+              />
+              <Form.FieldErrors />
+            {/snippet}
+          </Form.Control>
+        </Form.Field>
+
+        <Form.Field {form} name="password" class="grid gap-2">
+          <Form.Control>
+            {#snippet children({ props })}
+              <Form.Label>Password</Form.Label>
+              <InputPassword
+                {...props}
+                aria-invalid={$errors.password ? "true" : undefined}
+                bind:value={$formData.password}
+                placeholder="Enter password"
+                disabled={$submitting}
+                {...$constraints.password}
+              />
+              <Form.FieldErrors />
+            {/snippet}
+          </Form.Control>
+        </Form.Field>
+      </Card.Content>
+
+      <Card.Footer>
+        <Button
+          type="submit"
+          class="mt-3 flex w-full gap-x-2"
+          disabled={$submitting || !isValid() || isError()}
+        >
+          <span>Login</span>
+          {#if $submitting}
+            <Loading />
+          {/if}
+        </Button>
+      </Card.Footer>
+    </form>
+  </Card.Root>
+</div>
diff --git a/src/routes/+page.ts b/src/routes/+page.ts
new file mode 100644
index 0000000..99ac97a
--- /dev/null
+++ b/src/routes/+page.ts
@@ -0,0 +1,17 @@
+import { loginSchema } from "$lib/schemas/login";
+import { superValidate } from "sveltekit-superforms";
+import { zod } from "sveltekit-superforms/adapters";
+import type { PageLoad } from "./$types";
+import { useAuth } from "$lib/hooks/auth.svelte";
+import { redirect } from "@sveltejs/kit";
+
+export const load: PageLoad = async () => {
+  const auth = useAuth();
+
+  if (auth.isValid()) return redirect(307, "/home");
+
+  const data = { email: "", password: "" };
+  const form = await superValidate(data, zod(loginSchema));
+
+  return { form };
+};
-- 
Muhammad Rizki


  parent reply	other threads:[~2025-01-19  0:40 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-19  0:38 [PATCH v1 00/16] Refactor GNU/Weeb Mail Site Muhammad Rizki
2025-01-19  0:38 ` [PATCH v1 01/16] feat(routes): configure page layout options Muhammad Rizki
2025-01-19  0:38 ` [PATCH v1 02/16] feat(fonts): add Google fonts Muhammad Rizki
2025-01-19  0:38 ` [PATCH v1 03/16] feat(components): add shadcn-svelte components Muhammad Rizki
2025-01-19  0:38 ` [PATCH v1 04/16] feat(deps): add `axios` as HTTP client Muhammad Rizki
2025-01-19  0:38 ` [PATCH v1 05/16] feat(deps): add `svelte-copy` dependency Muhammad Rizki
2025-01-19  0:38 ` [PATCH v1 06/16] feat(constants): add navigations and mail-config constant Muhammad Rizki
2025-01-19  0:39 ` [PATCH v1 07/16] feat(components): add loading spinner component Muhammad Rizki
2025-01-19  0:39 ` [PATCH v1 08/16] feat(components): add header component Muhammad Rizki
2025-01-19  0:39 ` [PATCH v1 09/16] feat: initial hooks, schemas, typings for the login functions Muhammad Rizki
2025-01-19  0:39 ` [PATCH v1 10/16] feat(components): add app-sidebar component Muhammad Rizki
2025-01-19  0:39 ` [PATCH v1 11/16] feat(routes): create initial settings page Muhammad Rizki
2025-01-19  0:39 ` [PATCH v1 12/16] feat(routes): add home page Muhammad Rizki
2025-01-19  0:39 ` [PATCH v1 13/16] feat(routes): add main layout for the protected routes Muhammad Rizki
2025-01-19  0:39 ` Muhammad Rizki [this message]
2025-01-19  0:39 ` [PATCH v1 15/16] chore(.gitignore): add patch files ignore Muhammad Rizki
2025-01-19  0:39 ` [PATCH v1 16/16] chore: update README.md Muhammad Rizki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    [email protected] \
    [email protected] \
    [email protected] \
    [email protected] \
    [email protected] \
    [email protected] \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox