add images and redesign hompeage into sections, fix the dark color
Build & Deploy / Build & Push Docker Image (push) Failing after 48s
Build & Deploy / Deploy to VPS (push) Has been skipped
Test / API Unit Tests (push) Failing after 5m2s
Test / Marketplace Unit Tests (push) Failing after 4m55s
Test / Admin Unit Tests (push) Successful in 9m37s
Test / Dashboard Unit Tests (push) Successful in 9m37s
Test / API Integration Tests (push) Successful in 9m54s
Build & Deploy / Build & Push Docker Image (push) Failing after 48s
Build & Deploy / Deploy to VPS (push) Has been skipped
Test / API Unit Tests (push) Failing after 5m2s
Test / Marketplace Unit Tests (push) Failing after 4m55s
Test / Admin Unit Tests (push) Successful in 9m37s
Test / Dashboard Unit Tests (push) Successful in 9m37s
Test / API Integration Tests (push) Successful in 9m54s
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 448 KiB After Width: | Height: | Size: 836 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 836 KiB |
@@ -8,7 +8,7 @@ import PublicShell from "@/components/layout/PublicShell";
|
||||
import { API_BASE } from "@/lib/api";
|
||||
import { marketplaceUrl } from "@/lib/urls";
|
||||
|
||||
const DASHBOARD_LOGO_SRC = "/dashboard/rentalcardrive.png";
|
||||
const DASHBOARD_LOGO_SRC = "/dashboard/rentaldrivego.png";
|
||||
|
||||
export default function ForgotPasswordPageClient({
|
||||
embedded = false,
|
||||
@@ -104,6 +104,7 @@ export default function ForgotPasswordPageClient({
|
||||
width={104}
|
||||
height={104}
|
||||
priority
|
||||
unoptimized
|
||||
className="h-24 w-24 rounded-[1.75rem] border border-stone-200 bg-white p-1.5 shadow-sm transition-colors dark:border-blue-800 dark:bg-blue-950"
|
||||
/>
|
||||
</a>
|
||||
|
||||
@@ -14,7 +14,7 @@ html.dark {
|
||||
--primary: #2563eb;
|
||||
--primary-hover: #1d4ed8;
|
||||
--accent: #f97316;
|
||||
--sidebar-bg: #0a1128;
|
||||
--sidebar-bg: #172554;
|
||||
--sidebar-text: #94a3b8;
|
||||
--sidebar-active: #ffffff;
|
||||
|
||||
@@ -26,9 +26,9 @@ html.dark {
|
||||
}
|
||||
|
||||
html.dark {
|
||||
--bg-elevated: rgb(11 25 55 / 0.78);
|
||||
--border-accent: rgb(30 60 140 / 0.40);
|
||||
--glass-bg: rgb(11 25 55 / 0.65);
|
||||
--bg-elevated: rgb(23 37 84 / 0.82);
|
||||
--border-accent: rgb(30 64 175 / 0.40);
|
||||
--glass-bg: rgb(23 37 84 / 0.72);
|
||||
--shadow-card: 0 30px 80px rgba(0, 0, 0, 0.36);
|
||||
--shadow-glow: 0 0 20px rgba(249, 115, 22, 0.25);
|
||||
}
|
||||
@@ -41,7 +41,7 @@ html.dark {
|
||||
body {
|
||||
@apply text-blue-950 antialiased transition-colors dark:text-slate-100;
|
||||
background-image:
|
||||
linear-gradient(180deg, #ffffff 0%, #f5f8ff 28%, #eef4ff 58%, #ffffff 100%);
|
||||
linear-gradient(180deg, #ffffff 0%, #fafafa 28%, #f5f5f5 58%, #ffffff 100%);
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
@@ -51,12 +51,12 @@ html.dark {
|
||||
|
||||
html.dark body {
|
||||
background-image:
|
||||
linear-gradient(180deg, #0a1128 0%, #0d1b38 35%, #07101e 100%);
|
||||
linear-gradient(180deg, #172554 0%, #1b3068 35%, #0f1a40 100%);
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.fleet-dashboard-shell {
|
||||
--fleet-bg-primary: #f5f8ff;
|
||||
--fleet-bg-primary: #ffffff;
|
||||
--fleet-bg-elevated: #ffffff;
|
||||
--fleet-glass-bg: rgb(255 255 255 / 0.82);
|
||||
--fleet-card-bg: rgb(255 255 255 / 0.72);
|
||||
@@ -73,32 +73,32 @@ html.dark body {
|
||||
background:
|
||||
radial-gradient(ellipse at 20% 20%, rgb(37 99 235 / 0.10) 0%, transparent 56%),
|
||||
radial-gradient(ellipse at 82% 72%, rgb(249 115 22 / 0.08) 0%, transparent 54%),
|
||||
linear-gradient(180deg, #ffffff 0%, #f5f8ff 35%, #edf4ff 100%);
|
||||
linear-gradient(180deg, #ffffff 0%, #fafafa 35%, #f5f5f5 100%);
|
||||
color: var(--fleet-text-primary);
|
||||
}
|
||||
|
||||
html.dark .fleet-dashboard-shell {
|
||||
--fleet-bg-primary: #0a0f1a;
|
||||
--fleet-bg-elevated: #111827;
|
||||
--fleet-glass-bg: rgb(15 25 45 / 0.66);
|
||||
--fleet-card-bg: rgb(30 58 95 / 0.28);
|
||||
--fleet-border-subtle: rgb(59 130 246 / 0.14);
|
||||
--fleet-bg-primary: #172554;
|
||||
--fleet-bg-elevated: #1e3a8a;
|
||||
--fleet-glass-bg: rgb(23 37 84 / 0.78);
|
||||
--fleet-card-bg: rgb(23 37 84 / 0.72);
|
||||
--fleet-border-subtle: rgb(30 64 175 / 0.22);
|
||||
--fleet-text-primary: #e8edf5;
|
||||
--fleet-text-secondary: #8899b4;
|
||||
--fleet-accent-blue: #3b82f6;
|
||||
--fleet-accent-blue-light: #60a5fa;
|
||||
--fleet-accent-blue: #2e50f1;
|
||||
--fleet-accent-blue-light: #1e3de0;
|
||||
--fleet-accent-orange-light: #fb923c;
|
||||
--fleet-success: #10b981;
|
||||
--fleet-danger: #ef4444;
|
||||
background:
|
||||
radial-gradient(ellipse at 20% 20%, rgb(59 130 246 / 0.09) 0%, transparent 58%),
|
||||
radial-gradient(ellipse at 20% 20%, rgb(30 64 175 / 0.09) 0%, transparent 58%),
|
||||
radial-gradient(ellipse at 82% 72%, rgb(249 115 22 / 0.08) 0%, transparent 56%),
|
||||
linear-gradient(180deg, #0a0f1a 0%, #0d1728 46%, #08111f 100%);
|
||||
linear-gradient(180deg, #172554 0%, #1b3068 46%, #0f1a40 100%);
|
||||
}
|
||||
|
||||
.fleet-dashboard-shell * {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgb(59 130 246 / 0.22) transparent;
|
||||
scrollbar-color: rgb(1 26 148 / 0.22) transparent;
|
||||
}
|
||||
|
||||
.fleet-dashboard-shell *::-webkit-scrollbar {
|
||||
@@ -112,7 +112,7 @@ html.dark body {
|
||||
|
||||
.fleet-dashboard-shell *::-webkit-scrollbar-thumb {
|
||||
border-radius: 999px;
|
||||
background: rgb(59 130 246 / 0.22);
|
||||
background: rgb(1 26 148 / 0.22);
|
||||
}
|
||||
|
||||
.fleet-dashboard-shell .card,
|
||||
@@ -127,8 +127,8 @@ html.dark body {
|
||||
|
||||
.fleet-dashboard-shell .card:hover,
|
||||
.fleet-dashboard-shell .glass-card:hover {
|
||||
border-color: rgb(59 130 246 / 0.24);
|
||||
box-shadow: 0 18px 60px rgb(15 23 42 / 0.10), 0 0 20px rgb(59 130 246 / 0.10);
|
||||
border-color: rgb(1 26 148 / 0.24);
|
||||
box-shadow: 0 18px 60px rgb(15 23 42 / 0.10), 0 0 20px rgb(1 26 148 / 0.10);
|
||||
}
|
||||
|
||||
html.dark .fleet-dashboard-shell .card,
|
||||
@@ -138,33 +138,45 @@ html.dark body {
|
||||
|
||||
html.dark .fleet-dashboard-shell .card:hover,
|
||||
html.dark .fleet-dashboard-shell .glass-card:hover {
|
||||
box-shadow: 0 18px 60px rgb(0 0 0 / 0.26), 0 0 20px rgb(59 130 246 / 0.12);
|
||||
box-shadow: 0 18px 60px rgb(0 0 0 / 0.26), 0 0 20px rgb(1 26 148 / 0.12);
|
||||
}
|
||||
|
||||
.fleet-dashboard-shell .btn-primary {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 10px rgb(59 130 246 / 0.30);
|
||||
box-shadow: 0 2px 10px rgb(1 26 148 / 0.30);
|
||||
@apply rounded-lg bg-gradient-to-br from-blue-500 to-blue-700 text-white hover:from-blue-400 hover:to-blue-600;
|
||||
}
|
||||
|
||||
html.dark .fleet-dashboard-shell .btn-primary {
|
||||
@apply from-[#2e50f1] to-[#090385] hover:from-[#1e3de0] hover:to-[#2e50f1];
|
||||
}
|
||||
|
||||
.fleet-dashboard-shell .btn-secondary {
|
||||
border-color: rgb(59 130 246 / 0.18);
|
||||
background: rgb(59 130 246 / 0.08);
|
||||
border-color: rgb(1 26 148 / 0.18);
|
||||
background: rgb(1 26 148 / 0.08);
|
||||
color: var(--fleet-text-primary);
|
||||
@apply rounded-lg hover:border-blue-400/40 hover:bg-blue-500/15 hover:text-white;
|
||||
}
|
||||
|
||||
html.dark .fleet-dashboard-shell .btn-secondary {
|
||||
@apply hover:border-[#2e50f1]/40 hover:bg-[#2e50f1]/15;
|
||||
}
|
||||
|
||||
.fleet-dashboard-shell .input-field {
|
||||
border-color: rgb(59 130 246 / 0.14);
|
||||
background: rgb(59 130 246 / 0.07);
|
||||
border-color: rgb(1 26 148 / 0.14);
|
||||
background: rgb(1 26 148 / 0.07);
|
||||
color: var(--fleet-text-primary);
|
||||
@apply rounded-lg placeholder:text-slate-500 focus:border-blue-400 focus:ring-blue-500/20;
|
||||
}
|
||||
|
||||
html.dark .fleet-dashboard-shell .input-field {
|
||||
@apply focus:border-[#2e50f1] focus:ring-[#2e50f1]/20;
|
||||
}
|
||||
|
||||
.fleet-dashboard-shell .progress-bar {
|
||||
height: 6px;
|
||||
background: rgb(59 130 246 / 0.12);
|
||||
background: rgb(1 26 148 / 0.12);
|
||||
@apply rounded-full;
|
||||
}
|
||||
|
||||
@@ -172,13 +184,17 @@ html.dark body {
|
||||
@apply bg-gradient-to-r from-blue-500 to-blue-400;
|
||||
}
|
||||
|
||||
html.dark .fleet-dashboard-shell .progress-fill.blue {
|
||||
@apply from-[#2e50f1] to-[#1e3de0];
|
||||
}
|
||||
|
||||
.fleet-dashboard-shell .progress-fill.orange {
|
||||
@apply bg-gradient-to-r from-orange-500 to-orange-600;
|
||||
}
|
||||
|
||||
.fleet-dashboard-shell .badge-blue {
|
||||
border: 1px solid rgb(59 130 246 / 0.30);
|
||||
background: rgb(59 130 246 / 0.15);
|
||||
border: 1px solid rgb(1 26 148 / 0.30);
|
||||
background: rgb(1 26 148 / 0.15);
|
||||
color: var(--fleet-accent-blue-light);
|
||||
}
|
||||
|
||||
@@ -228,8 +244,8 @@ html.dark body {
|
||||
}
|
||||
|
||||
html.dark .glass-card {
|
||||
border-color: rgb(30 60 140 / 0.40);
|
||||
background-color: rgb(11 25 55 / 0.65);
|
||||
border-color: rgb(30 64 175 / 0.40);
|
||||
background-color: rgb(23 37 84 / 0.65);
|
||||
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.36);
|
||||
}
|
||||
|
||||
@@ -239,7 +255,7 @@ html.dark body {
|
||||
}
|
||||
|
||||
html.dark .progress-bar {
|
||||
background-color: rgb(30 60 140 / 0.3);
|
||||
background-color: rgb(30 64 175 / 0.3);
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
@@ -255,7 +271,7 @@ html.dark body {
|
||||
}
|
||||
|
||||
html.dark .progress-fill.blue {
|
||||
@apply bg-gradient-to-r from-blue-400 to-blue-300;
|
||||
@apply bg-gradient-to-r from-[#2e50f1] to-[#1e3de0];
|
||||
}
|
||||
|
||||
html.dark .progress-fill.orange {
|
||||
@@ -303,8 +319,8 @@ html.dark body {
|
||||
}
|
||||
|
||||
html.dark .card {
|
||||
border-color: rgb(30 60 140 / 0.40);
|
||||
background-color: rgb(11 25 55 / 0.72);
|
||||
border-color: rgb(30 64 175 / 0.40);
|
||||
background-color: rgb(23 37 84 / 0.72);
|
||||
}
|
||||
|
||||
.badge-green {
|
||||
@@ -312,7 +328,7 @@ html.dark body {
|
||||
}
|
||||
|
||||
.badge-blue {
|
||||
@apply inline-flex items-center rounded-full bg-blue-100 px-2.5 py-0.5 text-xs font-medium text-blue-700 dark:bg-blue-950/40 dark:text-blue-300;
|
||||
@apply inline-flex items-center rounded-full bg-blue-100 px-2.5 py-0.5 text-xs font-medium text-blue-700 dark:bg-[#2e50f1]/40 dark:text-[#1e3de0];
|
||||
}
|
||||
|
||||
.badge-amber {
|
||||
@@ -324,7 +340,7 @@ html.dark body {
|
||||
}
|
||||
|
||||
.badge-gray {
|
||||
@apply inline-flex items-center rounded-full bg-stone-100 px-2.5 py-0.5 text-xs font-medium text-stone-600 dark:bg-blue-950/40 dark:text-slate-300;
|
||||
@apply inline-flex items-center rounded-full bg-stone-100 px-2.5 py-0.5 text-xs font-medium text-stone-600 dark:bg-[#2e50f1]/40 dark:text-slate-300;
|
||||
}
|
||||
|
||||
.badge-purple {
|
||||
@@ -349,20 +365,20 @@ html.dark body {
|
||||
|
||||
@layer utilities {
|
||||
.dark .bg-slate-50 {
|
||||
background-color: rgb(7 16 46);
|
||||
background-color: #172554;
|
||||
}
|
||||
|
||||
.dark .bg-white {
|
||||
background-color: rgb(11 25 55);
|
||||
background-color: rgb(23 37 84 / 0.78);
|
||||
}
|
||||
|
||||
.dark .bg-white\/90 {
|
||||
background-color: rgb(11 25 55 / 0.9);
|
||||
background-color: rgb(23 37 84 / 0.9);
|
||||
}
|
||||
|
||||
.dark .border-slate-200,
|
||||
.dark .border-stone-200 {
|
||||
border-color: rgb(30 60 140 / 0.50);
|
||||
border-color: rgb(30 64 175 / 0.50);
|
||||
}
|
||||
|
||||
.dark .text-slate-900 {
|
||||
@@ -370,22 +386,22 @@ html.dark body {
|
||||
}
|
||||
|
||||
.dark .text-slate-700 {
|
||||
color: rgb(203 213 225);
|
||||
color: rgb(214 211 209);
|
||||
}
|
||||
|
||||
.dark .text-slate-600,
|
||||
.dark .text-stone-500 {
|
||||
color: rgb(148 163 184);
|
||||
color: rgb(168 162 158);
|
||||
}
|
||||
|
||||
.dark .text-slate-500,
|
||||
.dark .text-slate-400,
|
||||
.dark .text-stone-400 {
|
||||
color: rgb(100 116 139);
|
||||
color: rgb(120 113 108);
|
||||
}
|
||||
|
||||
.dark .hover\:bg-slate-100:hover {
|
||||
background-color: rgb(20 42 90);
|
||||
background-color: rgb(30 58 138 / 0.4);
|
||||
}
|
||||
|
||||
.dark .hover\:text-slate-900:hover {
|
||||
|
||||
@@ -17,8 +17,8 @@ export const metadata: Metadata = {
|
||||
title: 'RentalDriveGo Dashboard',
|
||||
description: 'Manage your rental car business',
|
||||
icons: {
|
||||
icon: '/dashboard/icon.svg',
|
||||
shortcut: '/dashboard/icon.svg',
|
||||
icon: '/icon.svg',
|
||||
shortcut: '/icon.svg',
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import ResetPasswordPageClient from "./reset-password/ResetPasswordPageClient";
|
||||
import ForgotPasswordPage from "./forgot-password/page";
|
||||
import ResetPasswordPage from "./reset-password/page";
|
||||
import AcceptInvitePage from "./onboarding/accept-invite/page";
|
||||
import SignUpForm from "./sign-up/[[...sign-up]]/SignUpForm";
|
||||
import SignUpPage from "./sign-up/[[...sign-up]]/page";
|
||||
|
||||
function collectText(node: unknown): string[] {
|
||||
if (node === null || node === undefined || typeof node === "boolean")
|
||||
@@ -56,6 +58,19 @@ describe("dashboard public auth pages", () => {
|
||||
expect(page.props.embedded).toBe(true);
|
||||
});
|
||||
|
||||
it("renders sign-up in embedded mode when requested", async () => {
|
||||
const page = await SignUpPage({
|
||||
searchParams: Promise.resolve({ embedded: "1" }),
|
||||
});
|
||||
|
||||
expect(isValidElement(page)).toBe(true);
|
||||
expect(page.type).toBe(React.Suspense);
|
||||
const child = page.props.children;
|
||||
expect(isValidElement(child)).toBe(true);
|
||||
expect(child.type).toBe(SignUpForm);
|
||||
expect(child.props.embedded).toBe(true);
|
||||
});
|
||||
|
||||
it("renders reset-password in embedded mode for the public shell route", () => {
|
||||
const page = ResetPasswordPage();
|
||||
|
||||
|
||||
@@ -240,7 +240,6 @@ function ResetShell({
|
||||
<main className="flex min-h-[calc(100vh-80px)] items-center justify-center px-4 py-12">
|
||||
<div className="w-full max-w-md">
|
||||
<div className="mb-8 text-center">
|
||||
<span className="text-xs font-semibold uppercase tracking-[0.24em] text-orange-700 dark:text-orange-400">RentalDriveGo</span>
|
||||
<h1 className="mt-3 text-3xl font-black tracking-tight text-stone-900 dark:text-stone-100">{title}</h1>
|
||||
{subtitle && <p className="mt-2 text-sm text-stone-500 dark:text-stone-400">{subtitle}</p>}
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { adminUrl, marketplaceUrl } from "@/lib/urls";
|
||||
import { API_BASE, EMPLOYEE_PROFILE_KEY } from "@/lib/api";
|
||||
import { toPublicDashboardPath } from "@/lib/dashboardPaths";
|
||||
|
||||
const DASHBOARD_LOGO_SRC = "/dashboard/rentalcardrive.png";
|
||||
const DASHBOARD_LOGO_SRC = "/dashboard/rentaldrivego.png";
|
||||
|
||||
function notifyParent(message: Record<string, unknown>) {
|
||||
if (typeof window === "undefined" || window.parent === window) return;
|
||||
@@ -184,13 +184,11 @@ export default function SignInPageClient({
|
||||
width={104}
|
||||
height={104}
|
||||
priority
|
||||
unoptimized
|
||||
className="h-24 w-24 rounded-[1.75rem] border border-stone-200/80 bg-white/85 p-1.5 shadow-sm transition-colors dark:border-blue-800 dark:bg-blue-950/80"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<p className="mt-5 text-xs font-bold uppercase tracking-[0.28em] text-orange-700 dark:text-orange-300">
|
||||
RentalDriveGo
|
||||
</p>
|
||||
<p className="mt-2 text-sm text-stone-600 dark:text-stone-300">
|
||||
{dict.subtitle}
|
||||
</p>
|
||||
|
||||
@@ -1,17 +1,46 @@
|
||||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
import { useState } from "react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { apiFetch } from "@/lib/api";
|
||||
import PublicShell from "@/components/layout/PublicShell";
|
||||
import { useDashboardI18n } from "@/components/I18nProvider";
|
||||
import { marketplaceUrl } from "@/lib/urls";
|
||||
|
||||
export default function SignUpForm() {
|
||||
const { language, setLanguage } = useDashboardI18n();
|
||||
const DASHBOARD_LOGO_SRC = "/dashboard/rentaldrivego.png";
|
||||
|
||||
function notifyParent(message: Record<string, unknown>) {
|
||||
if (typeof window === "undefined" || window.parent === window) return;
|
||||
window.parent.postMessage(message, "*");
|
||||
}
|
||||
|
||||
function withAuthQuery(
|
||||
path: string,
|
||||
params: { embedded: boolean; language: "en" | "fr" | "ar"; theme: string },
|
||||
) {
|
||||
const search = new URLSearchParams({
|
||||
lang: params.language,
|
||||
theme: params.theme,
|
||||
});
|
||||
|
||||
if (params.embedded) search.set("embedded", "1");
|
||||
|
||||
return `${path}?${search.toString()}`;
|
||||
}
|
||||
|
||||
export default function SignUpForm({
|
||||
embedded = false,
|
||||
}: {
|
||||
embedded?: boolean;
|
||||
}) {
|
||||
const { language, theme, setLanguage, setTheme } = useDashboardI18n();
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const requestedLanguage = searchParams.get("lang");
|
||||
const requestedTheme = searchParams.get("theme");
|
||||
const initializedFromQuery = useRef(false);
|
||||
const initialLanguage =
|
||||
requestedLanguage === "en" ||
|
||||
requestedLanguage === "fr" ||
|
||||
@@ -29,9 +58,79 @@ export default function SignUpForm() {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [success, setSuccess] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (initializedFromQuery.current) return;
|
||||
|
||||
if (
|
||||
(requestedLanguage === "en" ||
|
||||
requestedLanguage === "fr" ||
|
||||
requestedLanguage === "ar") &&
|
||||
requestedLanguage !== language
|
||||
) {
|
||||
setLanguage(requestedLanguage);
|
||||
setPreferredLanguage(requestedLanguage);
|
||||
}
|
||||
|
||||
if (
|
||||
(requestedTheme === "light" || requestedTheme === "dark") &&
|
||||
requestedTheme !== theme
|
||||
) {
|
||||
setTheme(requestedTheme);
|
||||
}
|
||||
|
||||
initializedFromQuery.current = true;
|
||||
}, [
|
||||
language,
|
||||
requestedLanguage,
|
||||
requestedTheme,
|
||||
setLanguage,
|
||||
setTheme,
|
||||
theme,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!initializedFromQuery.current) return;
|
||||
if (language !== preferredLanguage) setPreferredLanguage(language);
|
||||
}, [language, preferredLanguage]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!initializedFromQuery.current) return;
|
||||
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
let changed = false;
|
||||
|
||||
if (params.get("lang") !== preferredLanguage) {
|
||||
params.set("lang", preferredLanguage);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (params.get("theme") !== theme) {
|
||||
params.set("theme", theme);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (embedded && params.get("embedded") !== "1") {
|
||||
params.set("embedded", "1");
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (!changed) return;
|
||||
|
||||
const nextQuery = params.toString();
|
||||
router.replace(nextQuery ? `${pathname}?${nextQuery}` : pathname, {
|
||||
scroll: false,
|
||||
});
|
||||
}, [embedded, pathname, preferredLanguage, router, searchParams, theme]);
|
||||
|
||||
useEffect(() => {
|
||||
const currentPath =
|
||||
window.location.pathname + (window.location.search || "");
|
||||
notifyParent({ type: "rentaldrivego:embedded-path", path: currentPath });
|
||||
}, [pathname, searchParams]);
|
||||
|
||||
const dict = {
|
||||
en: {
|
||||
title: "Create your workspace",
|
||||
title: "Create account",
|
||||
subtitle: "Enter your email and password to get started.",
|
||||
email: "Email",
|
||||
emailPlaceholder: "you@company.com",
|
||||
@@ -39,7 +138,7 @@ export default function SignUpForm() {
|
||||
passwordPlaceholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
||||
passwordHint: "Minimum 8 characters",
|
||||
languageLabel: "Preferred language",
|
||||
create: "Create workspace",
|
||||
create: "Create account",
|
||||
creating: "Creating\u2026",
|
||||
alreadyHave: "Already have an account?",
|
||||
signIn: "Sign in",
|
||||
@@ -51,7 +150,7 @@ export default function SignUpForm() {
|
||||
successSignIn: "Go to sign in",
|
||||
},
|
||||
fr: {
|
||||
title: "Cr\u00e9ez votre espace",
|
||||
title: "Cr\u00e9er un compte",
|
||||
subtitle: "Saisissez votre email et mot de passe pour commencer.",
|
||||
email: "Email",
|
||||
emailPlaceholder: "vous@entreprise.com",
|
||||
@@ -59,7 +158,7 @@ export default function SignUpForm() {
|
||||
passwordPlaceholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
||||
passwordHint: "Minimum 8 caract\u00e8res",
|
||||
languageLabel: "Langue pr\u00e9f\u00e9r\u00e9e",
|
||||
create: "Cr\u00e9er mon espace",
|
||||
create: "Cr\u00e9er un compte",
|
||||
creating: "Cr\u00e9ation\u2026",
|
||||
alreadyHave: "Vous avez d\u00e9j\u00e0 un compte ?",
|
||||
signIn: "Se connecter",
|
||||
@@ -72,7 +171,7 @@ export default function SignUpForm() {
|
||||
},
|
||||
ar: {
|
||||
title:
|
||||
"\u0623\u0646\u0634\u0626 \u0645\u0633\u0627\u062d\u0629 \u0639\u0645\u0644\u0643",
|
||||
"\u0623\u0646\u0634\u0626 \u062d\u0633\u0627\u0628\u064b\u0627",
|
||||
subtitle:
|
||||
"\u0623\u062f\u062e\u0644 \u0628\u0631\u064a\u062f\u0643 \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a \u0648\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0644\u0644\u0628\u062f\u0621.",
|
||||
email:
|
||||
@@ -85,7 +184,7 @@ export default function SignUpForm() {
|
||||
languageLabel:
|
||||
"\u0627\u0644\u0644\u063a\u0629 \u0627\u0644\u0645\u0641\u0636\u0644\u0629",
|
||||
create:
|
||||
"\u0623\u0646\u0634\u0626 \u0627\u0644\u0645\u0633\u0627\u062d\u0629",
|
||||
"\u0623\u0646\u0634\u0626 \u062d\u0633\u0627\u0628\u064b\u0627",
|
||||
creating:
|
||||
"\u062c\u0627\u0631\u064d \u0627\u0644\u0625\u0646\u0634\u0627\u0621\u2026",
|
||||
alreadyHave:
|
||||
@@ -105,6 +204,12 @@ export default function SignUpForm() {
|
||||
},
|
||||
}[preferredLanguage];
|
||||
|
||||
const signInHref = withAuthQuery("/sign-in", {
|
||||
embedded,
|
||||
language: preferredLanguage,
|
||||
theme,
|
||||
});
|
||||
|
||||
async function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
@@ -135,17 +240,18 @@ export default function SignUpForm() {
|
||||
|
||||
if (success) {
|
||||
return (
|
||||
<PublicShell hideHeaderActions>
|
||||
<main className="flex flex-1 items-center justify-center px-4 py-16">
|
||||
<PublicShell embedded={embedded} hideFooter hideHeaderActions>
|
||||
<main className="flex flex-1 items-center justify-center px-4 py-12">
|
||||
<div className="w-full max-w-md text-center">
|
||||
<div className="flex justify-center mb-6">
|
||||
<Image
|
||||
src="/dashboard/rentalcardrive.png"
|
||||
src={DASHBOARD_LOGO_SRC}
|
||||
alt="RentalDriveGo"
|
||||
width={80}
|
||||
height={80}
|
||||
width={104}
|
||||
height={104}
|
||||
priority
|
||||
className="h-20 w-20 rounded-[1.5rem] border border-stone-200/80 bg-white/85 p-1.5 shadow-sm dark:border-blue-800 dark:bg-blue-950/80"
|
||||
unoptimized
|
||||
className="h-24 w-24 rounded-[1.75rem] border border-stone-200/80 bg-white/85 p-1.5 shadow-sm transition-colors dark:border-blue-800 dark:bg-blue-950/80"
|
||||
/>
|
||||
</div>
|
||||
<div className="rounded-[2rem] border border-stone-200/80 bg-white/82 p-8 shadow-[0_30px_80px_rgba(28,25,23,0.08)] backdrop-blur dark:border-blue-900 dark:bg-blue-950/78">
|
||||
@@ -156,7 +262,8 @@ export default function SignUpForm() {
|
||||
{dict.successMessage.replace("{email}", email)}
|
||||
</p>
|
||||
<a
|
||||
href="/sign-in"
|
||||
href={signInHref}
|
||||
target={embedded ? "_self" : undefined}
|
||||
className="mt-6 inline-flex justify-center rounded-full bg-orange-600 px-6 py-3 text-sm font-semibold text-white transition hover:bg-orange-700 dark:bg-orange-500 dark:hover:bg-orange-400"
|
||||
>
|
||||
{dict.successSignIn}
|
||||
@@ -169,23 +276,24 @@ export default function SignUpForm() {
|
||||
}
|
||||
|
||||
return (
|
||||
<PublicShell hideHeaderActions>
|
||||
<main className="flex flex-1 items-center justify-center px-4 py-16">
|
||||
<PublicShell embedded={embedded} hideFooter hideHeaderActions>
|
||||
<main className="flex flex-1 items-center justify-center px-4 py-12">
|
||||
<div className="w-full max-w-md">
|
||||
<div className="mb-8 text-center">
|
||||
<div className="flex justify-center">
|
||||
<a href={marketplaceUrl} target="_top">
|
||||
<Image
|
||||
src="/dashboard/rentalcardrive.png"
|
||||
src={DASHBOARD_LOGO_SRC}
|
||||
alt="RentalDriveGo"
|
||||
width={80}
|
||||
height={80}
|
||||
width={104}
|
||||
height={104}
|
||||
priority
|
||||
className="h-20 w-20 rounded-[1.5rem] border border-stone-200/80 bg-white/85 p-1.5 shadow-sm dark:border-blue-800 dark:bg-blue-950/80"
|
||||
unoptimized
|
||||
className="h-24 w-24 rounded-[1.75rem] border border-stone-200/80 bg-white/85 p-1.5 shadow-sm transition-colors dark:border-blue-800 dark:bg-blue-950/80"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<h1 className="mt-4 text-2xl font-black tracking-[-0.03em] text-blue-950 dark:text-stone-50">
|
||||
<h1 className="mt-3 text-3xl font-black tracking-tight text-stone-900 dark:text-stone-100">
|
||||
{dict.title}
|
||||
</h1>
|
||||
<p className="mt-2 text-sm text-stone-600 dark:text-stone-300">
|
||||
@@ -281,32 +389,6 @@ export default function SignUpForm() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span className="mb-1.5 block text-sm font-medium text-stone-700 dark:text-stone-200">
|
||||
{dict.languageLabel} <span className="text-red-500">*</span>
|
||||
</span>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
{(["en", "fr", "ar"] as const).map((lang) => (
|
||||
<button
|
||||
key={lang}
|
||||
type="button"
|
||||
onClick={() => setPreferredLanguage(lang)}
|
||||
className={`rounded-2xl border py-3 text-sm font-semibold transition ${
|
||||
preferredLanguage === lang
|
||||
? "border-blue-900 bg-blue-900 text-white dark:bg-orange-500 dark:border-orange-400"
|
||||
: "border-stone-200 bg-white text-stone-600 hover:border-stone-300 hover:bg-stone-50 dark:border-blue-800 dark:bg-blue-950/50 dark:text-stone-300 dark:hover:border-blue-600"
|
||||
}`}
|
||||
>
|
||||
{lang === "en"
|
||||
? "English"
|
||||
: lang === "fr"
|
||||
? "Fran\u00e7ais"
|
||||
: "\u0627\u0644\u0639\u0631\u0628\u064a\u0629"}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
@@ -319,7 +401,7 @@ export default function SignUpForm() {
|
||||
<p className="mt-6 text-center text-sm text-stone-500 dark:text-stone-400">
|
||||
{dict.alreadyHave}{" "}
|
||||
<a
|
||||
href="/sign-in"
|
||||
href={signInHref}
|
||||
className="font-semibold text-orange-700 hover:text-orange-800 dark:text-orange-300 dark:hover:text-orange-200"
|
||||
>
|
||||
{dict.signIn}
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
import { Suspense } from 'react'
|
||||
import SignUpForm from './SignUpForm'
|
||||
import { Suspense } from "react";
|
||||
import SignUpForm from "./SignUpForm";
|
||||
|
||||
export default async function SignUpPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<Record<string, string | string[] | undefined>>;
|
||||
}) {
|
||||
const params = await searchParams;
|
||||
const embedded = params.embedded === "1";
|
||||
|
||||
export default function SignUpPage() {
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<SignUpForm />
|
||||
<SignUpForm embedded={embedded} />
|
||||
</Suspense>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -75,11 +75,12 @@ export default function VerifyEmailPage() {
|
||||
<div className="w-full max-w-md text-center">
|
||||
<div className="flex justify-center mb-6">
|
||||
<Image
|
||||
src="/dashboard/rentalcardrive.png"
|
||||
src="/dashboard/rentaldrivego.png"
|
||||
alt="RentalDriveGo"
|
||||
width={80}
|
||||
height={80}
|
||||
priority
|
||||
unoptimized
|
||||
className="h-20 w-20 rounded-[1.5rem] border border-stone-200/80 bg-white/85 p-1.5 shadow-sm dark:border-blue-800 dark:bg-blue-950/80"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useEffect, useRef, useState } from "react";
|
||||
import { useDashboardI18n } from "@/components/I18nProvider";
|
||||
import { marketplaceUrl } from "@/lib/urls";
|
||||
|
||||
const BRAND_LOGO_SRC = "/dashboard/rentaldrivego.jpeg";
|
||||
const BRAND_LOGO_SRC = "/dashboard/rentaldrivego.png";
|
||||
|
||||
const languageMeta = {
|
||||
en: { flag: "🇺🇸", shortLabel: "EN" },
|
||||
@@ -103,6 +103,7 @@ export default function PublicHeader({
|
||||
width={36}
|
||||
height={36}
|
||||
priority
|
||||
unoptimized
|
||||
className="h-8 w-8 rounded-md object-contain sm:h-9 sm:w-9"
|
||||
/>
|
||||
<span>RentalDriveGo</span>
|
||||
|
||||
Reference in New Issue
Block a user