Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"build-storybook": "storybook build",
"openapi:generate": "openapi-generator-cli generate -i ./openapi.json -g typescript-fetch -o ./src/generated/api",
"openapi:export": "cargo run --manifest-path ../backend/Cargo.toml --bin export_openapi -- ./openapi.json",
"openapi": "pnpm run openapi:export && pnpm run openapi:generate"
"openapi": "pnpm run openapi:export && pnpm run openapi:generate",
"verify": "vue-tsc --noEmit && vp lint && vp fmt --check"
},
"dependencies": {
"@elysiajs/static": "1.4.10",
Expand Down Expand Up @@ -58,6 +59,7 @@
"vite": "catalog:",
"vite-bundle-analyzer": "1.3.8",
"vite-plus": "catalog:",
"vitest": "catalog:"
"vitest": "catalog:",
"vue-tsc": "3.3.2"
}
}
62 changes: 58 additions & 4 deletions apps/frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions apps/frontend/public/placeholder.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions apps/frontend/server/public/placeholder.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions apps/frontend/src/components/auth/SignIn.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script setup lang="ts">
import SignInForm from "./SignInForm.vue"

defineOptions({ name: "SignIn" })
</script>

<template>
<div class="bg-muted flex min-h-svh flex-col items-center justify-center p-6 md:p-10">
<div class="w-full max-w-sm md:max-w-4xl">
<SignInForm />
</div>
</div>
</template>
122 changes: 122 additions & 0 deletions apps/frontend/src/components/auth/SignInForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<script setup lang="ts">
import { ref } from "vue"
import { navigate } from "vike/client/router"
import { createApi } from "@/lib/api"
import { ResponseError } from "@/generated/api/runtime"
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import {
Field,
FieldDescription,
FieldGroup,
FieldLabel,
} from "@/components/ui/field"
import { Input } from "@/components/ui/input"

const email = ref("")
const password = ref("")
const errorMessage = ref("")
const isSubmitting = ref(false)

function loginErrorMessage(error: unknown): string {
if (error instanceof ResponseError) {
const status = error.response.status
if (status === 401) {
return "メールアドレスまたはパスワードが正しくありません"
}
if (status === 403) {
return "メールアドレスの確認が完了していません"
}
}
return "エラーが発生しました。しばらくしてからお試しください"
}

async function onSubmit(event: Event) {
event.preventDefault()
errorMessage.value = ""
isSubmitting.value = true

try {
await createApi().login({
loginRequest: {
email: email.value,
password: password.value,
},
})
await navigate("/")
} catch (error) {
errorMessage.value = loginErrorMessage(error)
} finally {
isSubmitting.value = false
}
}
</script>

<template>
<div class="flex flex-col gap-6">
<Card class="overflow-hidden p-0">
<CardContent class="grid p-0 md:grid-cols-2">
<form class="p-6 md:p-8" @submit="onSubmit">
<FieldGroup>
<div class="flex flex-col items-center gap-2 text-center">
<h1 class="text-2xl font-bold">
おかえりなさい
</h1>
<p class="text-muted-foreground text-sm text-balance">
メールアドレスを入力してサインインしてください
</p>
</div>
<div
v-if="errorMessage"
role="alert"
class="rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive"
>
{{ errorMessage }}
</div>
<Field>
<FieldLabel for="email">
メールアドレス
</FieldLabel>
<Input
id="email"
v-model="email"
type="email"
placeholder="m@example.com"
autocomplete="email"
required
/>
</Field>
<Field>
<FieldLabel for="password">
パスワード
</FieldLabel>
<Input
id="password"
v-model="password"
type="password"
autocomplete="current-password"
required
/>
</Field>
<Field>
<Button type="submit" class="w-full" :disabled="isSubmitting">
{{ isSubmitting ? "サインイン中…" : "サインイン" }}
</Button>
</Field>
<FieldDescription class="text-center">
アカウントをお持ちでない方は
<a href="/signup" class="underline underline-offset-4">新規登録</a>
</FieldDescription>
</FieldGroup>
</form>
<div class="bg-muted relative hidden md:block">
<img
src="/placeholder.svg"
alt=""
class="absolute inset-0 h-full w-full object-cover dark:brightness-[0.2] dark:grayscale"
>
</div>
</CardContent>
</Card>
</div>
</template>
13 changes: 13 additions & 0 deletions apps/frontend/src/components/auth/SignUp.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script setup lang="ts">
import SignUpForm from "./SignUpForm.vue"

defineOptions({ name: "SignUp" })
</script>

<template>
<div class="bg-muted flex min-h-svh flex-col items-center justify-center p-6 md:p-10">
<div class="w-full max-w-sm md:max-w-4xl">
<SignUpForm />
</div>
</div>
</template>
Loading