قالب صفحهٔ ورود (AuthPage)

صفحهٔ بیرون از قاب برای ورود، کد یک‌بارمصرف و بازیابی گذرواژه — وسط صفحه، نشان محصول، یک اقدام اصلی

معرفی

AuthPage قالب صفحه‌هایی است که کاربر پیش از ورود می‌بیند: ورود، کد یک‌بارمصرف، بازیابی گذرواژه. این صفحه‌ها بیرون از ProductFrame هستند (منو و سرِ قاب برای کاربری که وارد نشده معنایی ندارد) و قالب همه‌چیز را خودش دارد:

  • وسط صفحه، نشان و نام محصول بالای یک کارت باریک (--layout-auth-width، 400 پیکسل)؛
  • عنوان کار صفحه (تنها h1)، یک جمله زیرش، فیلدها (FormRow، برچسب بالای فیلد)؛
  • یک اقدام اصلی: دکمهٔ ثبت تمام‌عرض؛ پیوندهای متنی زیرش («فراموشی گذرواژه»)؛
  • خطای تلاش ناموفق در یک خلاصه بالای فیلدها با عنوان «درخواست انجام نشد» (نه «ذخیره انجام نشد» فرم‌ها)، اعلام‌شده و فوکوس‌شده؛
  • جای کنترل‌های زبان و پوسته در گوشهٔ بالای صفحه، و یک خط پایین کارت (مجوز، نسخه)؛
  • ناحیهٔ main صفحه را خودش می‌سازد.

چه زمانی استفاده کنیم: ورود، مرحلهٔ کد یک‌بارمصرف، بازیابی و تنظیم گذرواژهٔ تازه.

چه زمانی استفاده نکنیم:

  • هر صفحه‌ای پس از ورود: قالب همان صفحه داخل قاب (تغییر گذرواژه در تنظیمات یک FormPage است).
  • ثبت‌نام چندمرحله‌ای: WizardPage — داخل قاب اگر کاربر وارد شده، وگرنه همان مسیر بیرون از قاب.

استفاده

در Next.js، قاب لایهٔ گروه مسیرهای ورودشده است و صفحهٔ ورود در گروه دیگری بیرون از آن:

app/layout.tsx              ← html، body و Toaster؛ بی قاب
app/(app)/layout.tsx        ← <Frame>{children}</Frame>
app/(app)/mentions/page.tsx
app/(auth)/login/page.tsx   ← metadata و <Login />
app/(auth)/login/login.tsx  ← 'use client': <LoginScreen onSignedIn={() => router.push('/')} />
app/not-found.tsx           ← <Frame><UtilityPage kind="404" …/></Frame> (بیرون از هر گروه، پس قاب را خودش دارد)
'use client'
import * as React from 'react'
import Link from 'next/link'
import { useForm } from 'react-hook-form'
import { Button, Input } from '@partodata/ui'
import { Form, FormField } from '@partodata/ui/form'
import { AuthPage, FormRow } from '@partodata/ui/templates'

type SignIn = { email: string; password: string }

async function signIn(values: SignIn): Promise<void> {
  const response = await fetch('/api/session', { method: 'POST', body: JSON.stringify(values) })
  if (!response.ok) throw new Error(`session: ${response.status}`)
}

export function LoginScreen({ onSignedIn }: { onSignedIn: () => void }) {
  const form = useForm<SignIn>({ defaultValues: { email: '', password: '' } })
  const submit = form.handleSubmit(async (values) => {
    try {
      await signIn(values)
      onSignedIn()
    } catch {
      form.setError('root', { message: 'ایمیل یا گذرواژه درست نیست' })
    }
  })
  return (
    <Form {...form}>
      <AuthPage
        product={{ name: 'پایش منشن' }}
        title="ورود به حساب"
        description="با ایمیل سازمانی خود وارد شوید."
        onSubmit={submit}
        submitLabel="ورود"
        submitting={form.formState.isSubmitting}
        error={form.formState.errors.root?.message}
        links={
          <Button variant="link" asChild>
            <Link href="/reset">فراموشی گذرواژه</Link>
          </Button>
        }
      >
        <FormField
          control={form.control}
          name="email"
          rules={{ required: 'ایمیل را وارد کنید' }}
          render={({ field, fieldState }) => (
            <FormRow label="ایمیل" required error={fieldState.error?.message}>
              <Input kind="email" {...field} />
            </FormRow>
          )}
        />
        <FormField
          control={form.control}
          name="password"
          rules={{ required: 'گذرواژه را وارد کنید' }}
          render={({ field, fieldState }) => (
            <FormRow label="گذرواژه" required error={fieldState.error?.message}>
              <Input kind="password" {...field} />
            </FormRow>
          )}
        />
      </AuthPage>
    </Form>
  )
}

حالت‌ها و انواع

صفحهtitleفیلدهاsubmitLabellinks / back
ورود«ورود به حساب»ایمیل، گذرواژه«ورود»«فراموشی گذرواژه»
کد یک‌بارمصرف«کد تأیید را وارد کنید»InputOTP«تأیید کد»«ارسال دوباره کد»؛ back به «ورود»
بازیابی گذرواژه«بازیابی گذرواژه»ایمیل«ارسال پیوند بازیابی»back به «ورود»

خطای تلاش ناموفق هرگز نمی‌گوید کدام فیلد اشتباه بود («ایمیل یا گذرواژه درست نیست»).

راهنمای استفاده

بکنید

  • صفحه‌های پیش از ورود را در گروه مسیری بیرون از قاب بگذارید و هر کدام را یک AuthPage کنید.
  • product همان محصول قاب است؛ logo فقط نشان خود محصول.
  • پیوندهای کمکی را Button variant="link" با Link بنویسید، در links.

نکنید

  • AuthPage را داخل ProductFrame نگذارید (در محیط توسعه هشدار می‌دهد).
  • دکمهٔ دوم (ثبت‌نام، ورود با روش دیگر) را اقدام اصلی نکنید؛ پیوند متنی است.
  • کارت، h1 یا دکمهٔ ثبت خودتان نسازید.

Props

AuthPage

Prop

Type

AuthPageProduct

Prop

Type

دسترسی‌پذیری

  • صفحه ناحیهٔ main خودش را دارد و عنوان تنها h1 است؛ فرم با نام عنوان.
  • خطای تلاش ناموفق هشدار (role="alert") است و فوکوس می‌گیرد، هر بار که دوباره شکست بخورد.
  • فیلدها با FormRow برچسب، توضیح و پیام خطای خودشان را دارند.

کامپوننت‌های مرتبط