300 lines
10 KiB
TypeScript
300 lines
10 KiB
TypeScript
// routes/landlord/onboarding/profile.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,
|
|
setOnboardingStep,
|
|
} 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);
|
|
const onboardingStep = status?.onboarding_step ?? 0;
|
|
if (status?.onboarded_landlord && onboardingStep === 0) {
|
|
return new Response("", {
|
|
status: 303,
|
|
headers: { Location: "/landlord/properties/add" },
|
|
});
|
|
}
|
|
|
|
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);
|
|
const onboardingStep = status?.onboarding_step ?? 0;
|
|
if (status?.onboarded_landlord && onboardingStep === 0) {
|
|
return new Response("", {
|
|
status: 303,
|
|
headers: { Location: "/landlord/properties/add" },
|
|
});
|
|
}
|
|
|
|
const formData = await ctx.req.formData();
|
|
|
|
const phone = (formData.get("phone") || "").toString().trim();
|
|
const address_1 = (formData.get("address_1") || "").toString().trim();
|
|
const city = (formData.get("city") || "").toString().trim();
|
|
const state = (formData.get("state") || "").toString().trim();
|
|
const zip = (formData.get("zip") || "").toString().trim();
|
|
const country = (formData.get("country") || "").toString().trim();
|
|
|
|
if (!phone || !address_1 || !city || !state || !zip || !country) {
|
|
const user = await getUserById(user_id);
|
|
return page({
|
|
stateData,
|
|
user: user ? { ...user, id: publicId } : null,
|
|
error: "Phone and full address are required.",
|
|
});
|
|
}
|
|
|
|
await updateUser(user_id, {
|
|
name: (formData.get("name") || "").toString(),
|
|
email: (formData.get("email") || "").toString(),
|
|
phone: phone || "",
|
|
address_1: address_1 || "",
|
|
address_2: (formData.get("address_2") || "").toString(),
|
|
city: city || "",
|
|
state: state || "",
|
|
zip: zip || "",
|
|
country: country || "",
|
|
user_type: "landlord",
|
|
onboarded_landlord: true,
|
|
} as Partial<User>);
|
|
|
|
await setOnboardingStep(user_id, 2);
|
|
|
|
return new Response("", {
|
|
status: 302,
|
|
headers: { Location: "/landlord/onboarding/property-setup" },
|
|
});
|
|
},
|
|
});
|
|
|
|
export default define.page(function LandlordProfileSetup({ 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">
|
|
<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 Landlord Profile
|
|
</h2>
|
|
<p class="mt-2 text-center text-sm text-gray-600">
|
|
Tell us about yourself to get started.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-2xl">
|
|
<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 class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
|
<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="sm:col-span-2">
|
|
<label
|
|
for="address_1"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>
|
|
Street Address *
|
|
</label>
|
|
<input
|
|
id="address_1"
|
|
name="address_1"
|
|
type="text"
|
|
required
|
|
value={user?.address_1 || ""}
|
|
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="sm:col-span-2">
|
|
<label
|
|
for="address_2"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>
|
|
Apartment, suite, etc. (optional)
|
|
</label>
|
|
<input
|
|
id="address_2"
|
|
name="address_2"
|
|
type="text"
|
|
value={user?.address_2 || ""}
|
|
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="city"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>
|
|
City *
|
|
</label>
|
|
<input
|
|
id="city"
|
|
name="city"
|
|
type="text"
|
|
required
|
|
value={user?.city || ""}
|
|
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="state"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>
|
|
State/Province *
|
|
</label>
|
|
<input
|
|
id="state"
|
|
name="state"
|
|
type="text"
|
|
required
|
|
value={user?.state || ""}
|
|
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="zip"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>
|
|
ZIP/Postal Code *
|
|
</label>
|
|
<input
|
|
id="zip"
|
|
name="zip"
|
|
type="text"
|
|
required
|
|
value={user?.zip || ""}
|
|
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="country"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>
|
|
Country *
|
|
</label>
|
|
<select
|
|
id="country"
|
|
name="country"
|
|
required
|
|
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
|
>
|
|
<option value="US" selected={user?.country === "US"}>
|
|
United States
|
|
</option>
|
|
<option value="CA" selected={user?.country === "CA"}>
|
|
Canada
|
|
</option>
|
|
<option value="UK" selected={user?.country === "UK"}>
|
|
United Kingdom
|
|
</option>
|
|
<option value="AU" selected={user?.country === "AU"}>
|
|
Australia
|
|
</option>
|
|
</select>
|
|
</div>
|
|
</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 Properties
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
});
|