175 lines
5.3 KiB
TypeScript

// routes/tenant/onboarding/index.tsx
import { define } from "../../../utils.ts";
import { page } from "fresh";
import type { SessionCookie } from "../../auth/callback.ts";
import { getUserById, updateUser } from "../../../services/userService.ts";
import {
getOnboardingStatus,
markRoleOnboarded,
} from "../../../services/onboardingService.ts";
import { User } from "../../../db/interfaces.ts";
import { createPublicId } from "../../../helpers.ts";
export const handler = define.handlers({
async GET(ctx) {
const stateData = ctx.state.data as SessionCookie;
const { user_id } = stateData;
const publicId = stateData.user_id
? await createPublicId(stateData.user_id)
: "";
const status = await getOnboardingStatus(user_id);
if (status?.onboarded_tenant) {
return new Response("", {
status: 303,
headers: { Location: "/tenant/dashboard" },
});
}
const user = await getUserById(user_id);
return page({ stateData, user: user ? { ...user, id: publicId } : null });
},
async POST(ctx) {
const stateData = ctx.state.data as SessionCookie;
const { user_id } = stateData;
const publicId = stateData.user_id
? await createPublicId(stateData.user_id)
: "";
const status = await getOnboardingStatus(user_id);
if (status?.onboarded_tenant) {
return new Response("", {
status: 303,
headers: { Location: "/tenant/dashboard" },
});
}
const formData = await ctx.req.formData();
const name = (formData.get("name") || "").toString().trim();
const email = (formData.get("email") || "").toString().trim();
const phone = (formData.get("phone") || "").toString().trim();
if (!name || !email || !phone) {
const user = await getUserById(user_id);
return page({
stateData,
user: user ? { ...user, id: publicId } : null,
error: "Name, email, and phone are required.",
});
}
await updateUser(user_id, {
name,
email,
phone,
user_type: "tenant",
onboarded_tenant: true,
} as Partial<User>);
await markRoleOnboarded(user_id, "tenant");
return new Response(null, {
status: 303,
headers: { Location: "/tenant/dashboard" },
});
},
});
export default define.page(function TenantOnboarding({ data }) {
const { stateData: _stateData, user, error } = data as {
stateData: SessionCookie;
user: User | null;
error?: string;
};
return (
<div class="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8 tenant-route">
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900">
Complete Your Tenant Profile
</h2>
<p class="mt-2 text-center text-sm text-gray-600">
We just need a few details to get you started.
</p>
</div>
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div class="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
{error && (
<div class="mb-4 bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded">
{error}
</div>
)}
<form method="POST" class="space-y-6">
<div>
<label
for="name"
class="block text-sm font-medium text-gray-700"
>
Full Name *
</label>
<input
id="name"
name="name"
type="text"
required
value={user?.name || ""}
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
/>
</div>
<div>
<label
for="email"
class="block text-sm font-medium text-gray-700"
>
Email Address *
</label>
<input
id="email"
name="email"
type="email"
required
value={user?.email || ""}
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
/>
</div>
<div>
<label
for="phone"
class="block text-sm font-medium text-gray-700"
>
Phone Number *
</label>
<input
id="phone"
name="phone"
type="tel"
required
value={user?.phone || ""}
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
/>
</div>
<div class="flex justify-end pt-6">
<button
type="submit"
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
Continue to Dashboard
</button>
</div>
</form>
</div>
</div>
</div>
);
});