This commit is contained in:
IGNY8 VPS (Salman)
2025-12-08 06:15:35 +00:00
parent 156742d679
commit 4e9d8af768
5 changed files with 1733 additions and 107 deletions

View File

@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from "react";
import { useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import { ChevronLeftIcon, EyeCloseIcon, EyeIcon } from "../../icons";
import Label from "../form/Label";
@@ -6,15 +6,6 @@ import Input from "../form/input/InputField";
import Checkbox from "../form/input/Checkbox";
import { useAuthStore } from "../../store/authStore";
type Plan = {
id: number;
name: string;
price?: number;
billing_cycle?: string;
is_active?: boolean;
included_credits?: number;
};
export default function SignUpForm() {
const [showPassword, setShowPassword] = useState(false);
const [isChecked, setIsChecked] = useState(false);
@@ -26,43 +17,10 @@ export default function SignUpForm() {
username: "",
accountName: "",
});
const [plans, setPlans] = useState<Plan[]>([]);
const [selectedPlanId, setSelectedPlanId] = useState<number | null>(null);
const [plansLoading, setPlansLoading] = useState(true);
const [error, setError] = useState("");
const navigate = useNavigate();
const { register, loading } = useAuthStore();
const apiBaseUrl = useMemo(
() => import.meta.env.VITE_BACKEND_URL || "https://api.igny8.com/api",
[]
);
useEffect(() => {
const loadPlans = async () => {
setPlansLoading(true);
try {
const res = await fetch(`${apiBaseUrl}/v1/auth/plans/`, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
const data = await res.json();
const list: Plan[] = data?.results || data || [];
const activePlans = list.filter((p) => p.is_active !== false);
setPlans(activePlans);
if (activePlans.length > 0) {
setSelectedPlanId(activePlans[0].id);
}
} catch (e) {
// keep empty list; surface error on submit if no plan
console.error("Failed to load plans", e);
} finally {
setPlansLoading(false);
}
};
loadPlans();
}, [apiBaseUrl]);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
@@ -82,15 +40,11 @@ export default function SignUpForm() {
return;
}
if (!selectedPlanId) {
setError("Please select a plan to continue");
return;
}
try {
// Generate username from email if not provided
const username = formData.username || formData.email.split("@")[0];
// No plan_id needed - backend auto-assigns free trial
await register({
email: formData.email,
password: formData.password,
@@ -98,21 +52,15 @@ export default function SignUpForm() {
first_name: formData.firstName,
last_name: formData.lastName,
account_name: formData.accountName,
plan_id: selectedPlanId,
});
// Redirect to plan selection after successful registration
navigate("/account/plans", { replace: true });
// Hard fallback in case navigation is blocked by router state
setTimeout(() => {
if (window.location.pathname !== "/account/plans") {
window.location.assign("/account/plans");
}
}, 500);
// Redirect to dashboard/sites instead of payment page
navigate("/sites", { replace: true });
} catch (err: any) {
setError(err.message || "Registration failed. Please try again.");
}
};
return (
<div className="flex flex-col flex-1 w-full overflow-y-auto lg:w-1/2 no-scrollbar">
<div className="w-full max-w-md mx-auto mb-5 sm:pt-10">
@@ -128,10 +76,10 @@ export default function SignUpForm() {
<div>
<div className="mb-5 sm:mb-8">
<h1 className="mb-2 font-semibold text-gray-800 text-title-sm dark:text-white/90 sm:text-title-md">
Sign Up
Start Your Free Trial
</h1>
<p className="text-sm text-gray-500 dark:text-gray-400">
Enter your email and password to sign up!
No credit card required. 2,000 AI credits to get started.
</p>
</div>
<div>
@@ -195,7 +143,7 @@ export default function SignUpForm() {
</div>
)}
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2">
{/* <!-- First Name --> */}
{/* First Name */}
<div className="sm:col-span-1">
<Label>
First Name<span className="text-error-500">*</span>
@@ -207,10 +155,9 @@ export default function SignUpForm() {
value={formData.firstName}
onChange={handleChange}
placeholder="Enter your first name"
required
/>
</div>
{/* <!-- Last Name --> */}
{/* Last Name */}
<div className="sm:col-span-1">
<Label>
Last Name<span className="text-error-500">*</span>
@@ -222,11 +169,10 @@ export default function SignUpForm() {
value={formData.lastName}
onChange={handleChange}
placeholder="Enter your last name"
required
/>
</div>
</div>
{/* <!-- Email --> */}
{/* Email */}
<div>
<Label>
Email<span className="text-error-500">*</span>
@@ -238,10 +184,9 @@ export default function SignUpForm() {
value={formData.email}
onChange={handleChange}
placeholder="Enter your email"
required
/>
</div>
{/* <!-- Account Name --> */}
{/* Account Name */}
<div>
<Label>Account Name (optional)</Label>
<Input
@@ -253,32 +198,7 @@ export default function SignUpForm() {
placeholder="Workspace / Company name"
/>
</div>
{/* <!-- Plan Selection --> */}
<div>
<Label>
Select Plan<span className="text-error-500">*</span>
</Label>
<select
className="w-full px-3 py-2 border border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-900 text-sm"
value={selectedPlanId ?? ""}
onChange={(e) => setSelectedPlanId(Number(e.target.value))}
disabled={plansLoading || plans.length === 0}
>
{plansLoading && <option>Loading plans...</option>}
{!plansLoading && plans.length === 0 && (
<option value="">No plans available</option>
)}
{plans.map((plan) => (
<option key={plan.id} value={plan.id}>
{plan.name}
{plan.price ? ` - $${plan.price}/${plan.billing_cycle || "month"}` : ""}
</option>
))}
</select>
</div>
{/* <!-- Password --> */}
{/* Password */}
<div>
<Label>
Password<span className="text-error-500">*</span>
@@ -291,7 +211,6 @@ export default function SignUpForm() {
name="password"
value={formData.password}
onChange={handleChange}
required
/>
<span
onClick={() => setShowPassword(!showPassword)}
@@ -305,7 +224,7 @@ export default function SignUpForm() {
</span>
</div>
</div>
{/* <!-- Checkbox --> */}
{/* Terms Checkbox */}
<div className="flex items-center gap-3">
<Checkbox
className="w-5 h-5"
@@ -323,14 +242,14 @@ export default function SignUpForm() {
</span>
</p>
</div>
{/* <!-- Button --> */}
{/* Submit Button */}
<div>
<button
type="submit"
disabled={loading}
className="flex items-center justify-center w-full px-4 py-3 text-sm font-medium text-white transition rounded-lg bg-brand-500 shadow-theme-xs hover:bg-brand-600 disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? "Signing up..." : "Sign Up"}
{loading ? "Creating your account..." : "Start Free Trial"}
</button>
</div>
</div>
@@ -338,7 +257,7 @@ export default function SignUpForm() {
<div className="mt-5">
<p className="text-sm font-normal text-center text-gray-700 dark:text-gray-400 sm:text-start">
Already have an account? {""}
Already have an account?{" "}
<Link
to="/signin"
className="text-brand-500 hover:text-brand-600 dark:text-brand-400"