Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions apps/web/app/(org)/dashboard/caps/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,6 @@ export default async function CapsPage({
redirect("/login");
}

if (!user.name || user.name.length <= 1) {
redirect("/onboarding");
}

const userId = user.id;
const page = Number(searchParams.page) || 1;
const limit = Number(searchParams.limit) || 15;
Expand Down
20 changes: 1 addition & 19 deletions apps/web/app/(org)/login/form.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import { NODE_ENV } from "@cap/env";
import { Button, Input, LogoBadge } from "@cap/ui";
import {
faArrowLeft,
Expand Down Expand Up @@ -343,19 +342,6 @@ export function LoginForm() {
.
</motion.p>
</motion.div>
{emailSent && (
<motion.button
layout
className="pt-3 mx-auto text-sm underline text-gray-10 hover:text-gray-8"
onClick={() => {
setEmailSent(false);
setEmail("");
setLoading(false);
}}
>
Click to restart sign in process
</motion.button>
)}
</Suspense>
</motion.div>
</motion.div>
Expand Down Expand Up @@ -438,11 +424,7 @@ const NormalLogin = ({
disabled={loading || emailSent}
icon={<FontAwesomeIcon className="mr-1 size-4" icon={faEnvelope} />}
>
{emailSent
? NODE_ENV === "development"
? "Email sent to your terminal"
: "Email sent to your inbox"
: "Login with email"}
Login with email
</MotionButton>
{/* {NODE_ENV === "development" && (
<div className="flex justify-center items-center px-6 py-3 mt-3 bg-red-600 rounded-xl">
Expand Down
65 changes: 33 additions & 32 deletions apps/web/app/(org)/onboarding/Onboarding.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,46 @@
"use client";

import { Button, Input } from "@cap/ui";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { toast } from "sonner";
import { UpgradeModal } from "@/components/UpgradeModal";

export const Onboarding = () => {
const router = useRouter();
const [firstNameInput, setFirstNameInput] = useState("");
const [loading, setLoading] = useState(false);
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [showUpgradeModal, setShowUpgradeModal] = useState(false);

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const onboardingRequest = async () => {
const response = await fetch("/api/settings/onboarding", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ firstName, lastName }),
});

setLoading(true);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const formData = new FormData(e.currentTarget);
const firstName = formData.get("firstName") as string;
const lastName = formData.get("lastName") as string;
return response.json();
};

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
try {
const response = await fetch("/api/settings/onboarding", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ firstName, lastName }),
});

if (response.ok) {
const data = await response.json();
setLoading(true);
const response = await onboardingRequest();

if (!data.isMemberOfOrganization) setShowUpgradeModal(true);

toast.success("Name updated successfully");
router.push("/dashboard");
if (!response.isMemberOfOrganization) {
setShowUpgradeModal(true);
} else {
toast.error("Failed to update name");
// Force complete page reload to bypass React cache
window.location.replace("/dashboard");
}
} catch (error) {
console.error("Error updating name:", error);
toast.error("An error occurred while updating name");
} catch {
toast.error("Failed to complete onboarding");
} finally {
setLoading(false);
}
Expand All @@ -62,8 +60,8 @@ export const Onboarding = () => {
placeholder="First name"
name="firstName"
required
value={firstNameInput}
onChange={(e) => setFirstNameInput(e.target.value)}
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
</div>
<div className="flex flex-col space-y-1">
Expand All @@ -72,16 +70,19 @@ export const Onboarding = () => {
id="lastName"
name="lastName"
placeholder="Last name"
required
value={lastName}
onChange={(e) => setLastName(e.target.value)}
/>
</div>
</div>
<Button
disabled={!firstNameInput}
disabled={!firstName || !lastName || loading}
className="mx-auto mt-6 w-full"
type="submit"
spinner={loading}
>
Complete
{loading ? "Submitting..." : "Submit"}
</Button>
</form>

Expand All @@ -90,7 +91,7 @@ export const Onboarding = () => {
onOpenChange={(open) => {
setShowUpgradeModal(open);
if (!open) {
router.push("/dashboard");
window.location.replace("/dashboard");
}
}}
/>
Expand Down
9 changes: 5 additions & 4 deletions apps/web/app/(org)/verify-otp/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,10 @@ export function VerifyOTPForm({
</p>
</div>

<div className="flex justify-center gap-2 mb-6">
<div className="flex gap-2 justify-center mb-6">
{code.map((digit, index) => (
<input
key={index}
key={index.toString()}
ref={(el) => (inputRefs.current[index] = el)}
type="text"
inputMode="numeric"
Expand All @@ -188,7 +188,7 @@ export function VerifyOTPForm({
.replace(/\D/g, "");
handleChange(0, pastedData);
}}
className="w-12 h-14 text-center text-xl font-semibold bg-gray-1 border border-gray-5 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
className="w-12 h-14 text-xl font-semibold text-center rounded-lg border transition-all bg-gray-1 border-gray-5 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
disabled={handleVerify.isPending || handleVerify.isSuccess}
/>
))}
Expand All @@ -197,6 +197,7 @@ export function VerifyOTPForm({
<Button
variant="primary"
className="w-full"
spinner={isVerifying}
onClick={() => handleVerify.mutate()}
disabled={code.some((digit) => !digit) || isVerifying}
>
Expand All @@ -208,7 +209,7 @@ export function VerifyOTPForm({
type="button"
onClick={() => handleResend.mutate()}
disabled={handleResend.isPending}
className="text-sm text-gray-10 hover:text-gray-12 underline transition-colors"
className="text-sm underline transition-colors text-gray-10 hover:text-gray-12"
>
{handleResend.isPending
? "Sending..."
Expand Down
5 changes: 4 additions & 1 deletion apps/web/app/api/settings/onboarding/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
users,
} from "@cap/database/schema";
import { and, eq, ne, or } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import type { NextRequest } from "next/server";

export async function POST(request: NextRequest) {
Expand All @@ -15,7 +16,6 @@ export async function POST(request: NextRequest) {

if (!user) {
console.error("User not found");

return Response.json({ error: true }, { status: 401 });
}

Expand Down Expand Up @@ -91,6 +91,9 @@ export async function POST(request: NextRequest) {
.where(eq(users.id, user.id));
}

revalidatePath("/onboarding");
revalidatePath("/dashboard");

return Response.json(
{
success: true,
Expand Down
5 changes: 4 additions & 1 deletion apps/web/components/UpgradeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export const UpgradeModal = ({ open, onOpenChange }: UpgradeModalProps) => {
<span className="mr-3 text-gray-12">Users:</span>
<div className="flex items-center">
<button
type="button"
onClick={() =>
proQuantity > 1 && setProQuantity(proQuantity - 1)
}
Expand All @@ -246,6 +247,7 @@ export const UpgradeModal = ({ open, onOpenChange }: UpgradeModalProps) => {
className="mx-auto w-6 text-sm tabular-nums text-center text-gray-12"
/>
<button
type="button"
onClick={() => setProQuantity(proQuantity + 1)}
className="flex justify-center items-center w-8 h-8 rounded-r-md bg-gray-4 hover:bg-gray-5"
>
Expand All @@ -265,6 +267,7 @@ export const UpgradeModal = ({ open, onOpenChange }: UpgradeModalProps) => {
{proLoading ? "Loading..." : "Upgrade to Cap Pro"}
</Button>
<button
type="button"
className="mt-2 w-full max-w-sm h-14 text-base rounded-xl hover:underline text-gray-11 hover:text-gray-12"
onClick={() => onOpenChange(false)}
>
Expand All @@ -277,7 +280,7 @@ export const UpgradeModal = ({ open, onOpenChange }: UpgradeModalProps) => {
<div className="grid grid-cols-1 gap-8 md:grid-cols-2">
{proFeatures.map((feature, index) => (
<div
key={index}
key={index.toString()}
className="flex flex-col justify-center items-center"
>
<div className="mb-3.5 bg-gray-5 rounded-full size-10 flex items-center justify-center">
Expand Down
Loading