244 lines
8.3 KiB
TypeScript
244 lines
8.3 KiB
TypeScript
// routes/tenant/reminders/index.tsx
|
|
import { define } from "../../../utils.ts";
|
|
import { page } from "fresh";
|
|
import {
|
|
deleteReminder,
|
|
getRemindersByUserId,
|
|
markReminderCompleted,
|
|
} from "../../../services/reminderService.ts";
|
|
import { Reminder } from "../../../db/interfaces.ts";
|
|
|
|
interface RemindersPageData {
|
|
reminders: Reminder[];
|
|
error?: string;
|
|
}
|
|
|
|
export const handler = define.handlers({
|
|
async GET(ctx) {
|
|
const { user_id } = ctx.state.data;
|
|
|
|
if (!user_id) {
|
|
return new Response("", {
|
|
status: 302,
|
|
headers: { Location: "/auth/login" },
|
|
});
|
|
}
|
|
|
|
try {
|
|
const reminders = await getRemindersByUserId(user_id);
|
|
return page<RemindersPageData>({
|
|
reminders,
|
|
});
|
|
} catch (error) {
|
|
console.error("Error loading reminders:", error);
|
|
return page<RemindersPageData>({
|
|
reminders: [],
|
|
error: "Failed to load reminders.",
|
|
});
|
|
}
|
|
},
|
|
|
|
async POST(ctx) {
|
|
const { user_id } = ctx.state.data;
|
|
|
|
if (!user_id) {
|
|
return new Response("", {
|
|
status: 302,
|
|
headers: { Location: "/auth/login" },
|
|
});
|
|
}
|
|
|
|
try {
|
|
const formData = await ctx.req.formData();
|
|
const action = formData.get("action") as string;
|
|
const reminderId = formData.get("reminder_id") as string;
|
|
|
|
if (!reminderId) {
|
|
return new Response("Missing reminder ID", { status: 400 });
|
|
}
|
|
|
|
if (action === "mark_completed") {
|
|
await markReminderCompleted(reminderId, true);
|
|
} else if (action === "delete") {
|
|
await deleteReminder(reminderId);
|
|
}
|
|
|
|
// Redirect back to the list
|
|
return new Response("", {
|
|
status: 302,
|
|
headers: { Location: "/tenant/reminders" },
|
|
});
|
|
} catch (error) {
|
|
console.error("Error processing reminder action:", error);
|
|
return new Response("Failed to process action", { status: 500 });
|
|
}
|
|
},
|
|
});
|
|
|
|
function ReminderStatusPill({ isCompleted }: { isCompleted: boolean }) {
|
|
const colorClass = isCompleted
|
|
? "bg-green-100 text-green-800"
|
|
: "bg-yellow-100 text-yellow-800";
|
|
const text = isCompleted ? "Completed" : "Pending";
|
|
return (
|
|
<span
|
|
class={`px-3 py-1 inline-flex text-xs leading-5 font-semibold rounded-full ${colorClass}`}
|
|
>
|
|
{text}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
export default define.page(function TenantReminders({ data }) {
|
|
const { reminders, error } = data as RemindersPageData;
|
|
|
|
const pendingReminders = reminders.filter((r) => !r.is_completed);
|
|
const completedReminders = reminders.filter((r) => r.is_completed);
|
|
|
|
return (
|
|
<div class="min-h-screen bg-gray-50">
|
|
{/* Header */}
|
|
<div class="bg-white shadow">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="py-6 flex justify-between items-center">
|
|
<h1 class="text-3xl font-bold text-gray-900">My Reminders</h1>
|
|
<a
|
|
href="/tenant/reminders/new"
|
|
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
|
>
|
|
+ New Reminder
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Main Content */}
|
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 py-8">
|
|
{error && (
|
|
<div class="mb-4">
|
|
<ReminderStatusPill isCompleted={false} />
|
|
</div>
|
|
)}
|
|
|
|
<div class="bg-white shadow overflow-hidden sm:rounded-lg">
|
|
<div class="px-4 py-5 sm:px-6 border-b border-gray-200">
|
|
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
|
Pending Reminders ({pendingReminders.length})
|
|
</h3>
|
|
</div>
|
|
<ul class="divide-y divide-gray-200">
|
|
{pendingReminders.length > 0
|
|
? (
|
|
pendingReminders.map((reminder) => (
|
|
<li class="px-6 py-4 flex items-center justify-between">
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm font-medium text-gray-900 truncate">
|
|
{reminder.title}
|
|
</p>
|
|
<p class="text-sm text-gray-500">
|
|
Due: {new Date(reminder.due_date).toLocaleDateString()}
|
|
</p>
|
|
{reminder.description && (
|
|
<p class="mt-1 text-xs text-gray-400">
|
|
{reminder.description}
|
|
</p>
|
|
)}
|
|
</div>
|
|
<div class="flex items-center space-x-4">
|
|
<ReminderStatusPill isCompleted={false} />
|
|
<form method="POST" class="inline-block">
|
|
<input
|
|
type="hidden"
|
|
name="reminder_id"
|
|
value={reminder.id}
|
|
/>
|
|
<input
|
|
type="hidden"
|
|
name="action"
|
|
value="mark_completed"
|
|
/>
|
|
<button
|
|
type="submit"
|
|
class="text-green-600 hover:text-green-900 text-sm font-medium"
|
|
>
|
|
Mark Complete
|
|
</button>
|
|
</form>
|
|
<form method="POST" class="inline-block">
|
|
<input
|
|
type="hidden"
|
|
name="reminder_id"
|
|
value={reminder.id}
|
|
/>
|
|
<input type="hidden" name="action" value="delete" />
|
|
<button
|
|
type="submit"
|
|
class="text-red-600 hover:text-red-900 text-sm font-medium"
|
|
>
|
|
Delete
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</li>
|
|
))
|
|
)
|
|
: (
|
|
<li class="px-6 py-4 text-center text-sm text-gray-500">
|
|
You have no pending reminders.
|
|
</li>
|
|
)}
|
|
</ul>
|
|
</div>
|
|
|
|
{/* Completed Reminders */}
|
|
<div class="mt-8 bg-white shadow overflow-hidden sm:rounded-lg">
|
|
<div class="px-4 py-5 sm:px-6 border-b border-gray-200">
|
|
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
|
Completed Reminders ({completedReminders.length})
|
|
</h3>
|
|
</div>
|
|
<ul class="divide-y divide-gray-200">
|
|
{completedReminders.length > 0
|
|
? (
|
|
completedReminders.map((reminder) => (
|
|
<li class="px-6 py-4 flex items-center justify-between bg-gray-50 opacity-70">
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm font-medium text-gray-900 line-through truncate">
|
|
{reminder.title}
|
|
</p>
|
|
<p class="text-sm text-gray-500">
|
|
Due: {new Date(reminder.due_date).toLocaleDateString()}
|
|
</p>
|
|
</div>
|
|
<div class="flex items-center space-x-4">
|
|
<ReminderStatusPill isCompleted />
|
|
<form method="POST" class="inline-block">
|
|
<input
|
|
type="hidden"
|
|
name="reminder_id"
|
|
value={reminder.id}
|
|
/>
|
|
<input type="hidden" name="action" value="delete" />
|
|
<button
|
|
type="submit"
|
|
class="text-red-600 hover:text-red-900 text-sm font-medium"
|
|
>
|
|
Delete
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</li>
|
|
))
|
|
)
|
|
: (
|
|
<li class="px-6 py-4 text-center text-sm text-gray-500">
|
|
No completed reminders.
|
|
</li>
|
|
)}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
});
|