Skip to content

Commit d03e80b

Browse files
authored
Merge pull request #1942 from AtCoder-NoviSteps/#1939
🎨 Add forgot_password page and link (#1939)
2 parents bdad650 + a157d16 commit d03e80b

File tree

8 files changed

+167
-7
lines changed

8 files changed

+167
-7
lines changed

src/lib/components/AuthForm.svelte

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
GUEST_USER_NAME,
1616
GUEST_USER_PASSWORD,
1717
// GUEST_USER_PASSWORD_FOR_LOCAL,
18+
LOGIN_LABEL,
1819
} from '$lib/constants/forms';
19-
import { HOME_PAGE, LOGIN_PAGE } from '$lib/constants/navbar-links';
20+
import { HOME_PAGE, LOGIN_PAGE, FORGOT_PASSWORD_PAGE } from '$lib/constants/navbar-links';
2021
2122
interface Props {
2223
// FIXME: 構造体に相当するものを利用した方が拡張・修正がしやすくなるかもしれせまん
@@ -89,6 +90,10 @@
8990
9091
const UNFOCUSABLE = -1;
9192
let showPassword = $state(false);
93+
94+
function isLoginForm(title: string): boolean {
95+
return title === LOGIN_LABEL;
96+
}
9297
</script>
9398

9499
<!-- FIXME: コンポーネントが巨大になってきたと思われるので、分割しましょう -->
@@ -185,12 +190,19 @@
185190
</div>
186191

187192
<!-- TODO: ログイン画面で、パスワードの記録・忘れた場合のリセット機能を追加 -->
188-
<!-- <div class="flex items-start">
189-
<Checkbox>Remember me</Checkbox>
190-
<a href="/" class="ml-auto text-sm text-primary-700 hover:underline dark:text-primary-500">
191-
Lost password?
192-
</a>
193-
</div> -->
193+
<!-- HACK: 認証ライブラリの移行・メールアドレスの登録・送信機能などが必要なため、暫定的に「アカウント移行機能」で対応 -->
194+
{#if isLoginForm(title)}
195+
<div class="flex items-start">
196+
<!-- <Checkbox>Remember me</Checkbox> -->
197+
198+
<a
199+
href={FORGOT_PASSWORD_PAGE}
200+
class="ml-auto text-sm text-primary-700 hover:underline dark:text-primary-500"
201+
>
202+
パスワードを忘れましたか?
203+
</a>
204+
</div>
205+
{/if}
194206

195207
<Button type="submit" class="w-full" disabled={$submitting || isSubmitting}>
196208
{submitButtonLabel}

src/lib/components/ExternalLinkWrapper.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
textColorInDarkMode?: string;
99
textOverflow?: string;
1010
iconSize?: number;
11+
ariaLabel?: string;
1112
useInlineFlex?: boolean;
1213
}
1314
@@ -18,13 +19,15 @@
1819
textColorInDarkMode = 'dark:text-primary-500',
1920
textOverflow = '',
2021
iconSize = 4,
22+
ariaLabel = '',
2123
useInlineFlex = true,
2224
}: Props = $props();
2325
</script>
2426

2527
<a
2628
href={url}
2729
class={`${useInlineFlex ? 'inline-flex' : ''} items-center font-medium ${textSize} text-primary-600 hover:underline ${textColorInDarkMode}`}
30+
aria-label={ariaLabel}
2831
target="_blank"
2932
rel="noreferrer"
3033
>

src/lib/constants/navbar-links.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export const HOME_PAGE = `/`;
22
export const ABOUT_PAGE = `/about`;
33
export const SIGNUP_PAGE = `/signup`;
44
export const LOGIN_PAGE = `/login`;
5+
export const FORGOT_PASSWORD_PAGE = `/forgot_password`;
56
export const WORKBOOKS_PAGE = `/workbooks`;
67
export const PROBLEMS_PAGE = `/problems`;
78

src/lib/constants/product-info.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ export const features = [
2828

2929
const X_BASE_URL = 'https://x.com/';
3030

31+
export const X_OFFICIAL_ACCOUNT_URL = `${X_BASE_URL}acnovisteps`;
32+
3133
export const members = [
3234
{ name: '@けんちょん', account: `${X_BASE_URL}drken1215` },
3335
{ name: '@hiro', account: `${X_BASE_URL}k_hiro1818` },

src/routes/+error.svelte

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script lang="ts">
2+
import { page } from '$app/state';
3+
4+
import { Heading, Button } from 'svelte-5-ui-lib';
5+
import HeadingOne from '$lib/components/HeadingOne.svelte';
6+
7+
import { HOME_PAGE } from '$lib/constants/navbar-links';
8+
</script>
9+
10+
<div
11+
class="container mx-auto md:w-4/5 lg:w-2/3 py-4 md:py-8 px-3 md:px-0 flex flex-col items-center"
12+
>
13+
<HeadingOne title="エラーが発生しました" />
14+
15+
{#if page.error}
16+
<Heading tag="h2" class="text-3xl mb-3 text-gray-900 dark:text-gray-300">
17+
{page.status}
18+
</Heading>
19+
20+
<p class="dark:text-gray-300">{page.error.message}</p>
21+
{/if}
22+
23+
<div class="flex justify-center mt-6">
24+
<Button href={HOME_PAGE} color="primary" class="px-6">
25+
{'ホームに戻る'}
26+
</Button>
27+
</div>
28+
</div>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { error } from '@sveltejs/kit';
2+
3+
import { FORBIDDEN } from '$lib/constants/http-response-status-codes';
4+
5+
export async function load({ locals }) {
6+
const session = await locals.auth.validate();
7+
8+
if (session) {
9+
error(
10+
FORBIDDEN,
11+
`ログイン中は、パスワードリセット / アカウント移行ページにアクセスできません。`,
12+
);
13+
}
14+
15+
return {};
16+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<script lang="ts">
2+
import { Heading, Card, Alert, Button, List, Li } from 'svelte-5-ui-lib';
3+
4+
import HeadingOne from '$lib/components/HeadingOne.svelte';
5+
6+
import ExternalLinkWrapper from '$lib/components/ExternalLinkWrapper.svelte';
7+
8+
import { X_OFFICIAL_ACCOUNT_URL } from '$lib/constants/product-info';
9+
import { LOGIN_PAGE } from '$lib/constants/navbar-links';
10+
import { LOGIN_LABEL } from '$lib/constants/forms';
11+
</script>
12+
13+
<!-- See: -->
14+
<!-- https://github.com/lucia-auth/example-sveltekit-email-password-2fa/blob/main/src/routes/forgot-password/%2Bpage.svelte -->
15+
<!-- https://svelte-5-ui-lib.codewithshin.com/components/card -->
16+
<div class="container mx-auto md:w-4/5 lg:w-2/3 py-4 md:py-8 px-3 md:px-0">
17+
<HeadingOne title="パスワードを忘れた場合の対応について" />
18+
19+
{@render passwordResetSection()}
20+
{@render accountMigrationGuideSection()}
21+
</div>
22+
23+
{#snippet passwordResetSection()}
24+
<Card size="xl" class="mb-5" padding="sm">
25+
<Heading tag="h2" class="text-xl mb-2 text-gray-900 dark:text-white">
26+
パスワードリセット機能
27+
</Heading>
28+
29+
<p class="mb-3 dark:text-gray-300">
30+
パスワードリセット機能は開発中です。しばらくお待ちください。
31+
</p>
32+
</Card>
33+
{/snippet}
34+
35+
{#snippet accountMigrationGuideSection()}
36+
<Card size="xl" padding="sm">
37+
<!-- Header -->
38+
<Heading tag="h2" class="text-xl mb-2 text-gray-900 dark:text-white">
39+
アカウント移行のご案内
40+
</Heading>
41+
42+
<p class="mb-3 dark:text-gray-300">
43+
お急ぎの場合は、<strong>回答履歴を新しいアカウントに移行</strong>することができます。
44+
</p>
45+
46+
<!-- Guide -->
47+
<Heading tag="h3" class="text-lg mb-2 text-gray-800 dark:text-gray-200">手順</Heading>
48+
49+
<List tag="ol" class="mb-5 pl-5 list-decimal dark:text-gray-300">
50+
<Li>
51+
<strong class="text-red-600">回答履歴を含まない</strong>新しいアカウントを用意してください
52+
</Li>
53+
<Li>
54+
以下の情報を準備してください:
55+
<List tag="ul" class="ml-5 mt-1 list-disc">
56+
<Li><strong>現在のアカウント名</strong>(パスワードを忘れたアカウント)</Li>
57+
<Li><strong>新しいアカウント名</strong>(移行先となるアカウント)</Li>
58+
</List>
59+
</Li>
60+
<Li>
61+
開発・運営チームの
62+
<ExternalLinkWrapper
63+
url={X_OFFICIAL_ACCOUNT_URL}
64+
description="公式アカウント"
65+
ariaLabel="Open official X account as a new tab"
66+
/>
67+
にダイレクトメッセージでご連絡ください
68+
</Li>
69+
<Li class="dark:text-gray-300">
70+
メッセージには「アカウント移行希望」と記載し、2. の情報をお伝えください</Li
71+
>
72+
</List>
73+
74+
<!-- Warnings -->
75+
<Alert color="red" class="mb-5">
76+
<Heading tag="h3" class="text-lg mb-2 text-red-500 dark:text-red-500">注意</Heading>
77+
78+
<List tag="ul" class="pl-5 list-disc">
79+
<Li>移行処理には1〜3日ほどかかる場合があります</Li>
80+
<Li>移行が完了しても、元のアカウントは削除されません</Li>
81+
<Li>移行後は新しいアカウントでログインしてください</Li>
82+
</List>
83+
</Alert>
84+
85+
<p class="dark:text-gray-300">
86+
ご不便をおかけして申し訳ござませんが、ご理解とご協力をお願いいたします。
87+
</p>
88+
89+
<!-- Back to login page -->
90+
<div class="flex justify-center mt-6">
91+
<Button href={LOGIN_PAGE} color="primary" class="px-6">
92+
{LOGIN_LABEL}ページに戻る
93+
</Button>
94+
</div>
95+
</Card>
96+
{/snippet}

src/routes/sitemap.xml/+server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ export const GET: RequestHandler = async () => {
6060
'/users/.*',
6161
'/workbooks/create.*',
6262
'/workbooks/edit/.*',
63+
// Pages for not-logged-in users
64+
'/forgot_password',
6365
// Deprecated page
6466
'/problems/\\[slug\\]',
6567
],

0 commit comments

Comments
 (0)