204 lines
6.9 KiB
TypeScript
204 lines
6.9 KiB
TypeScript
// routes/tenant/maintenance/new/index.tsx
|
|
import { define } from "../../../../utils.ts";
|
|
import { getLeasesByTenant } from "../../../../services/leaseService.ts";
|
|
import { createMaintenanceRequest } from "../../../../services/maintenanceRequestService.ts";
|
|
import { page } from "fresh";
|
|
import { MAINTENANCE_CATEGORIES, PRIORITY_LEVELS } from "./constants.ts";
|
|
import { FormField } from "./components/FormField.tsx";
|
|
import { SelectField } from "./components/SelectField.tsx";
|
|
import { TextAreaField } from "./components/TextAreaField.tsx";
|
|
import { AlertMessage } from "./components/AlertMessage.tsx";
|
|
import { PropertyInfo } from "./components/PropertyInfo.tsx";
|
|
import { EmergencyNotice } from "./components/EmergencyNotice.tsx";
|
|
import { FileUpload } from "./components/FileUpload.tsx";
|
|
import { MaintenanceFormData, NewMaintenancePageProps } from "./types.ts";
|
|
import { validateMaintenanceRequest } from "./utils/validation.ts";
|
|
|
|
export const handler = define.handlers({
|
|
async GET(ctx) {
|
|
const { user_id } = ctx.state.data;
|
|
|
|
try {
|
|
const leases = await getLeasesByTenant(user_id);
|
|
const currentLease = leases?.[0]; // Assuming tenant has one active lease
|
|
|
|
return page({
|
|
currentLease,
|
|
});
|
|
} catch (error) {
|
|
console.error("Error loading maintenance request form:", error);
|
|
return page({
|
|
error: "Failed to load form",
|
|
});
|
|
}
|
|
},
|
|
|
|
async POST(ctx) {
|
|
const { user_id } = ctx.state.data;
|
|
|
|
try {
|
|
const formData = await ctx.req.formData();
|
|
|
|
const requestData: MaintenanceFormData = {
|
|
tenant_id: user_id,
|
|
property_id: formData.get("property_id") as string,
|
|
title: formData.get("title") as string,
|
|
description: formData.get("description") as string,
|
|
priority: formData.get("priority") as string,
|
|
category: formData.get("category") as string,
|
|
status: "open",
|
|
};
|
|
|
|
const validationErrors = validateMaintenanceRequest(requestData);
|
|
if (validationErrors.length > 0) {
|
|
return page({
|
|
error: validationErrors.map((
|
|
err: { field: string; message: string },
|
|
) => `${err.field}: ${err.message}`).join(", "),
|
|
});
|
|
}
|
|
|
|
await createMaintenanceRequest(
|
|
requestData.property_id,
|
|
requestData.tenant_id,
|
|
requestData.title,
|
|
requestData.description,
|
|
requestData.priority,
|
|
);
|
|
|
|
return new Response("", {
|
|
status: 302,
|
|
headers: { Location: "/tenant/maintenance?success=true" },
|
|
});
|
|
} catch (error) {
|
|
console.error("Error creating maintenance request:", error);
|
|
return page({
|
|
error: "Failed to submit maintenance request. Please try again.",
|
|
});
|
|
}
|
|
},
|
|
});
|
|
|
|
export default define.page(
|
|
function NewMaintenanceRequest(
|
|
{ data }: NewMaintenancePageProps,
|
|
) {
|
|
const { currentLease, error } = data;
|
|
|
|
if (!currentLease) {
|
|
return (
|
|
<div class="min-h-screen bg-gray-50 flex items-center justify-center">
|
|
<div class="text-center">
|
|
<h1 class="text-2xl font-bold text-gray-900 mb-4">
|
|
No Active Lease
|
|
</h1>
|
|
<p class="text-gray-600">
|
|
You need an active lease to submit maintenance requests.
|
|
</p>
|
|
<a
|
|
href="/tenant/dashboard"
|
|
class="mt-4 inline-block text-blue-600 hover:text-blue-500"
|
|
>
|
|
Return to Dashboard
|
|
</a>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div class="min-h-screen bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
|
<div class="max-w-3xl mx-auto">
|
|
<div class="text-center mb-8">
|
|
<h2 class="text-3xl font-extrabold text-gray-900">
|
|
Submit Maintenance Request
|
|
</h2>
|
|
<p class="mt-2 text-sm text-gray-600">
|
|
Report an issue with your rental property
|
|
</p>
|
|
</div>
|
|
|
|
<div class="bg-white shadow sm:rounded-lg">
|
|
<div class="px-4 py-5 sm:p-6">
|
|
{error && (
|
|
<AlertMessage type="error">
|
|
{error}
|
|
</AlertMessage>
|
|
)}
|
|
|
|
<PropertyInfo currentLease={currentLease} />
|
|
|
|
<form method="POST" class="space-y-6">
|
|
<input
|
|
type="hidden"
|
|
name="property_id"
|
|
value={currentLease.property_id || ""}
|
|
/>
|
|
|
|
<FormField label="Issue Title" required>
|
|
<input
|
|
type="text"
|
|
name="title"
|
|
id="title"
|
|
required
|
|
placeholder="Brief description of the issue"
|
|
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
|
/>
|
|
</FormField>
|
|
|
|
<FormField label="Category" required>
|
|
<SelectField
|
|
id="category"
|
|
name="category"
|
|
options={MAINTENANCE_CATEGORIES}
|
|
required
|
|
/>
|
|
</FormField>
|
|
|
|
<FormField label="Priority Level" required>
|
|
<SelectField
|
|
id="priority"
|
|
name="priority"
|
|
options={PRIORITY_LEVELS}
|
|
required
|
|
/>
|
|
</FormField>
|
|
|
|
<FormField label="Detailed Description" required>
|
|
<TextAreaField
|
|
id="description"
|
|
name="description"
|
|
rows={6}
|
|
required
|
|
placeholder="Please provide a detailed description of the issue, including when it started, what you've tried, and any other relevant information..."
|
|
/>
|
|
</FormField>
|
|
|
|
<EmergencyNotice />
|
|
|
|
<FileUpload />
|
|
|
|
{/* Submit Button */}
|
|
<div class="flex justify-between pt-6">
|
|
<a
|
|
href="/tenant/dashboard"
|
|
class="inline-flex justify-center py-2 px-4 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
|
>
|
|
Cancel
|
|
</a>
|
|
<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"
|
|
>
|
|
Submit Request
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
},
|
|
);
|