Merge version_2_1782113692699 into main #2
@@ -2,11 +2,13 @@ import { Routes, Route } from 'react-router-dom';
|
||||
import Layout from './components/Layout';
|
||||
import HomePage from './pages/HomePage';
|
||||
|
||||
import RegisterPage from "@/pages/RegisterPage";
|
||||
export default function App() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route element={<Layout />}>
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/register" element={<RegisterPage />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
);
|
||||
|
||||
@@ -27,7 +27,9 @@ export default function Layout() {
|
||||
},
|
||||
{
|
||||
"name": "Testimonials", "href": "#testimonials"
|
||||
}
|
||||
},
|
||||
{ name: "Register", href: "/register" },
|
||||
|
||||
];
|
||||
|
||||
return (
|
||||
|
||||
168
src/pages/RegisterPage.tsx
Normal file
168
src/pages/RegisterPage.tsx
Normal file
@@ -0,0 +1,168 @@
|
||||
import React, { useState } from "react";
|
||||
import { routes } from "@/routes";
|
||||
import Input from "@/components/ui/Input";
|
||||
import Label from "@/components/ui/Label";
|
||||
import Button from "@/components/ui/Button";
|
||||
import { Check } from "lucide-react";
|
||||
|
||||
export default function RegisterPage() {
|
||||
const [step, setStep] = useState(1);
|
||||
const [formData, setFormData] = useState({
|
||||
companyName: "",
|
||||
email: "",
|
||||
password: "",
|
||||
theme: "light",
|
||||
});
|
||||
|
||||
const handleNext = () => setStep((s) => Math.min(s + 1, 3));
|
||||
const handlePrev = () => setStep((s) => Math.max(s - 1, 1));
|
||||
const handleRegister = () => {
|
||||
console.log("Mock Firebase Submission:"); console.log("-> Writing to 'tenant' collection:", { companyName: formData.companyName, theme: formData.theme }); console.log("-> Writing to 'registration' collection:", { email: formData.email, password: formData.password }); alert("登録が完了しました! (Registration Complete)");
|
||||
};
|
||||
|
||||
const steps = [
|
||||
{ id: 1, label: "基本情報" },
|
||||
{ id: 2, label: "テーマ選択" },
|
||||
{ id: 3, label: "完了" },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="min-h-svh bg-background text-foreground flex flex-col">
|
||||
<main className="flex-grow flex items-center justify-center p-6">
|
||||
<div className="w-full max-w-content-width bg-card text-foreground p-8 rounded-xl border border-foreground/10 shadow-sm card">
|
||||
<h1 className="text-2xl font-bold text-center">新規アカウント登録</h1>
|
||||
|
||||
{/* Stepper UI */}
|
||||
<div className="flex items-center justify-between relative">
|
||||
<div className="absolute left-0 top-5 -translate-y-1/2 w-full h-1 bg-foreground/10 -z-10 rounded-full"></div>
|
||||
<div
|
||||
className="absolute left-0 top-5 -translate-y-1/2 h-1 bg-primary-cta -z-10 rounded-full transition-all duration-500 ease-in-out"
|
||||
style={{ width: `${((step - 1) / 2) * 100}%` }}
|
||||
></div>
|
||||
|
||||
{steps.map((s) => (
|
||||
<div key={s.id} className="flex flex-col items-center gap-3 bg-card px-2">
|
||||
<div
|
||||
className={`w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold transition-colors duration-300 ${ step >= s.id ?"bg-primary-cta text-primary-cta-text"
|
||||
: "bg-card text-foreground/50 border-2 border-foreground/10"
|
||||
}`}
|
||||
>
|
||||
{step > s.id ? <Check className="w-5 h-5" /> : s.id}
|
||||
</div>
|
||||
<span className={`text-xs font-medium ${step >= s.id ?"text-foreground" : "text-foreground/50"}`}>
|
||||
{s.label}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Step 1: Basic Info */}
|
||||
{step === 1 && (
|
||||
<div className="space-y-5 animate-in fade-in slide-in-from-bottom-4 duration-500">
|
||||
<h2 className="text-lg font-semibold mb-4">ステップ 1: 基本情報</h2>
|
||||
<div>
|
||||
<Label className="mb-2 block">企業名 (テナント)</Label>
|
||||
<Input
|
||||
value={formData.companyName}
|
||||
onChange={(e) => setFormData({ ...formData, companyName: e.target.value })}
|
||||
placeholder="株式会社蟹江電機"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="mb-2 block">メールアドレス</Label>
|
||||
<Input
|
||||
type="email"
|
||||
value={formData.email}
|
||||
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
||||
placeholder="admin@example.com"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="mb-2 block">パスワード</Label>
|
||||
<Input
|
||||
type="password"
|
||||
value={formData.password}
|
||||
onChange={(e) => setFormData({ ...formData, password: e.target.value })}
|
||||
placeholder="••••••••"
|
||||
/>
|
||||
</div>
|
||||
<div className="pt-6">
|
||||
<Button text="次へ" onClick={handleNext} animate={false} className="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Step 2: Theme Selection */}
|
||||
{step === 2 && (
|
||||
<div className="space-y-5 animate-in fade-in slide-in-from-bottom-4 duration-500">
|
||||
<h2 className="text-lg font-semibold mb-4">ステップ 2: テーマ選択</h2>
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
{["light", "dark", "system"].map((t) => (
|
||||
<div
|
||||
key={t}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => setFormData({ ...formData, theme: t })}
|
||||
className={`p-4 border rounded-lg text-center cursor-pointer transition-all ${ formData.theme === t ?"border-primary-cta bg-primary-cta/10 text-primary-cta"
|
||||
: "border-foreground/10 hover:bg-foreground/5 text-foreground"
|
||||
}`}
|
||||
>
|
||||
<div className="font-medium capitalize">
|
||||
{t === "light" ? "ライト" : t === "dark" ? "ダーク" : "システム"}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="pt-6 flex gap-4">
|
||||
<div className="w-1/2">
|
||||
<Button text="戻る" variant="secondary" onClick={handlePrev} animate={false} className="w-full" />
|
||||
</div>
|
||||
<div className="w-1/2">
|
||||
<Button text="次へ" onClick={handleNext} animate={false} className="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Step 3: Complete */}
|
||||
{step === 3 && (
|
||||
<div className="space-y-5 animate-in fade-in slide-in-from-bottom-4 duration-500 text-center">
|
||||
<div className="w-16 h-16 bg-primary-cta/10 text-primary-cta rounded-full flex items-center justify-center mx-auto mb-4">
|
||||
<Check className="w-8 h-8" />
|
||||
</div>
|
||||
<h2 className="text-xl font-semibold mb-2">準備が完了しました</h2>
|
||||
<p className="text-sm text-foreground/60 mb-6">
|
||||
以下の内容でテナントと管理者アカウントを作成します。
|
||||
</p>
|
||||
|
||||
<div className="bg-foreground/5 p-4 rounded-lg text-left space-y-2 text-sm mb-8 border border-foreground/10">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-foreground/60">企業名:</span>
|
||||
<span className="font-medium">{formData.companyName || "未入力"}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-foreground/60">メール:</span>
|
||||
<span className="font-medium">{formData.email || "未入力"}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-foreground/60">テーマ:</span>
|
||||
<span className="font-medium capitalize">{formData.theme}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-2 flex gap-4">
|
||||
<div className="w-1/2">
|
||||
<Button text="戻る" variant="secondary" onClick={handlePrev} animate={false} className="w-full" />
|
||||
</div>
|
||||
<div className="w-1/2">
|
||||
<Button text="登録する" onClick={handleRegister} animate={false} className="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -6,4 +6,5 @@ export interface Route {
|
||||
|
||||
export const routes: Route[] = [
|
||||
{ path: '/', label: 'Home', pageFile: 'HomePage' },
|
||||
{ path: '/register', label: 'Register', pageFile: 'RegisterPage' },
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user