Apply patch [skip ci]

This commit is contained in:
open-swe-dev-andrinoid[bot] 2026-01-22 00:42:14 +00:00
parent 85e7247e4a
commit 2ab27763f9
12 changed files with 192 additions and 226 deletions

46
TODO.md
View File

@ -1,34 +1,56 @@
# Project TODO List
This document outlines the remaining tasks, incomplete features, and future development plans for the application.
This document outlines the remaining tasks, incomplete features, and future
development plans for the application.
## High Priority
- **Implement Payment Processing**: The current rent payment system in `routes/tenant/rent/pay/index.tsx` is a placeholder. It needs to be fully implemented with a payment provider like Stripe to handle real transactions securely.
- **Implement Payment Processing**: The current rent payment system in
`routes/tenant/rent/pay/index.tsx` is a placeholder. It needs to be fully
implemented with a payment provider like Stripe to handle real transactions
securely.
## Backend & API
- **Add Well-Known Endpoint**: Implement a `/.well-known/acme-challenge/:token` endpoint in `main.ts` to support services like Let's Encrypt for SSL certificate validation in production.
- **Enforce Database Constraints**: Ensure the `owner_id` field in the `AccessTokenResponse` interface is unique for each entry, as noted in `utils/database.ts`. This is crucial for maintaining data integrity.
- **Add Well-Known Endpoint**: Implement a `/.well-known/acme-challenge/:token`
endpoint in `main.ts` to support services like Let's Encrypt for SSL
certificate validation in production.
- **Enforce Database Constraints**: Ensure the `owner_id` field in the
`AccessTokenResponse` interface is unique for each entry, as noted in
`utils/database.ts`. This is crucial for maintaining data integrity.
## Feature Development
- **Complete Landlord Dashboard**: Flesh out all features under the `routes/landlord/` directory. This includes:
- **Complete Landlord Dashboard**: Flesh out all features under the
`routes/landlord/` directory. This includes:
- Property management
- Tenant invitation and management (`islands/LandlordInviteTenant.tsx`)
- Messaging with tenants (`islands/LandlordMessageThreads.tsx`)
- Financial tracking and reporting
- **Complete Tenant Dashboard**: Finalize all features under the `routes/tenant/` directory. This includes:
- **Complete Tenant Dashboard**: Finalize all features under the
`routes/tenant/` directory. This includes:
- Viewing lease documents
- Tracking rent payments and financial obligations
- Messaging with landlords (`islands/TenantMessageThreads.tsx`)
- Managing settings (`islands/TenantSettings.tsx`)
- **Enhance User Onboarding**: Improve the onboarding flow for both new landlords and tenants in `routes/onboarding/`.
- **Develop User Profile Management**: Complete the user profile editing and management features in `routes/user-profile/`.
- **Enhance User Onboarding**: Improve the onboarding flow for both new
landlords and tenants in `routes/onboarding/`.
- **Develop User Profile Management**: Complete the user profile editing and
management features in `routes/user-profile/`.
## Future Features & Refinements
- **AI/ML Feature Integration**: The advanced features found in the `islands/` directory need further development and integration into the user experience. This includes:
- **AI/ML Feature Integration**: The advanced features found in the `islands/`
directory need further development and integration into the user experience.
This includes:
- `BrainStudy.tsx`
- `Quizzing.tsx`
- `ImageGenerater.tsx`
- `VoiceRecorder.tsx`
- **Calendar Functionality**: Expand the calendar features in `routes/calendar/` and improve the `islands/FinancialCalendar.tsx` component to be more interactive and informative.
- **Document Management**: Build out a robust document upload, storage, and sharing system for leases, notices, and other rental-related documents.
- **Reminders and Notifications**: Implement a system for sending automated reminders for rent payments, lease renewals, and other important events.
- **Calendar Functionality**: Expand the calendar features in `routes/calendar/`
and improve the `islands/FinancialCalendar.tsx` component to be more
interactive and informative.
- **Document Management**: Build out a robust document upload, storage, and
sharing system for leases, notices, and other rental-related documents.
- **Reminders and Notifications**: Implement a system for sending automated
reminders for rent payments, lease renewals, and other important events.

View File

@ -75,8 +75,8 @@ export default function PaymentMethodsList(
if (decryptedData) {
const accountNumber = decryptedData;
// Show only last 4 digits
processedMethod.maskedAccountNumber =
"****" + accountNumber.slice(-4);
processedMethod.maskedAccountNumber = "****" +
accountNumber.slice(-4);
}
} catch (error) {
console.error("Failed to decrypt account number:", error);
@ -93,8 +93,8 @@ export default function PaymentMethodsList(
if (decryptedData) {
const routingNumber = decryptedData;
// Show only last 4 digits
processedMethod.maskedRoutingNumber =
"****" + routingNumber.slice(-4);
processedMethod.maskedRoutingNumber = "****" +
routingNumber.slice(-4);
}
} catch (error) {
console.error("Failed to decrypt routing number:", error);
@ -147,153 +147,155 @@ export default function PaymentMethodsList(
{popupAddPaymentMethodDialog}
<div class="space-y-4">
{processedMethods.length === 0 ? (
<div class="text-center py-12 bg-white rounded-lg shadow">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-16 w-16 mx-auto text-gray-400 mb-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"
/>
</svg>
<h3 class="text-lg font-medium text-gray-900 mb-2">
No payment methods
</h3>
<p class="text-gray-500 mb-6">
Add a payment method to get started with rent payments.
</p>
<button
type="button"
onClick={() => _setIsOpeningModal(true)}
class="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-6 rounded-lg transition-colors"
>
Add Payment Method
</button>
</div>
) : (
<>
<ul class="space-y-4">
{processedMethods.map((method) => (
<li
key={method.id}
class="bg-white rounded-lg shadow p-6 relative"
>
<div class="flex items-start justify-between">
<div class="flex-1">
<div class="flex items-center gap-2 mb-2">
<h3 class="text-lg font-semibold text-gray-900">
{method.bank_name || "Bank Account"}
</h3>
{method.is_default && (
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
Default
</span>
)}
</div>
<div class="space-y-1 text-sm text-gray-600">
<div>
<span class="font-medium">Type:</span>{" "}
{method.account_type === "checking"
? "Checking"
: method.account_type === "savings"
? "Savings"
: method.account_type || "Unknown"}
</div>
<div>
<span class="font-medium">Account:</span>{" "}
{method.maskedAccountNumber || "****"}
</div>
<div>
<span class="font-medium">Routing:</span>{" "}
{method.maskedRoutingNumber || "****"}
</div>
</div>
</div>
<div class="flex items-center gap-2 ml-4">
{!method.is_default && (
<button
type="button"
onClick={() => handleSetDefault(method.id!)}
class="text-blue-600 hover:text-blue-700 text-sm font-medium px-3 py-1.5 rounded border border-blue-600 hover:bg-blue-50 transition-colors"
>
Set Default
</button>
)}
<form
method="POST"
action="/api/delete/payment_method"
class="inline"
>
<input type="hidden" name="id" value={method.id} />
<input
type="hidden"
name="sender"
value={typeof location !== "undefined"
? location.pathname
: ""}
/>
<button
type="submit"
aria-label="Delete payment method"
class="text-red-600 hover:text-red-700 p-2 rounded hover:bg-red-50 transition-colors"
title="Delete payment method"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</button>
</form>
</div>
</div>
</li>
))}
</ul>
<div class="mt-6">
{processedMethods.length === 0
? (
<div class="text-center py-12 bg-white rounded-lg shadow">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-16 w-16 mx-auto text-gray-400 mb-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"
/>
</svg>
<h3 class="text-lg font-medium text-gray-900 mb-2">
No payment methods
</h3>
<p class="text-gray-500 mb-6">
Add a payment method to get started with rent payments.
</p>
<button
type="button"
onClick={() => _setIsOpeningModal(true)}
class="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-6 rounded-lg shadow transition-colors flex items-center justify-center gap-2"
class="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-6 rounded-lg transition-colors"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 4v16m8-8H4"
/>
</svg>
Add Payment Method
</button>
</div>
</>
)}
)
: (
<>
<ul class="space-y-4">
{processedMethods.map((method) => (
<li
key={method.id}
class="bg-white rounded-lg shadow p-6 relative"
>
<div class="flex items-start justify-between">
<div class="flex-1">
<div class="flex items-center gap-2 mb-2">
<h3 class="text-lg font-semibold text-gray-900">
{method.bank_name || "Bank Account"}
</h3>
{method.is_default && (
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
Default
</span>
)}
</div>
<div class="space-y-1 text-sm text-gray-600">
<div>
<span class="font-medium">Type:</span>{" "}
{method.account_type === "checking"
? "Checking"
: method.account_type === "savings"
? "Savings"
: method.account_type || "Unknown"}
</div>
<div>
<span class="font-medium">Account:</span>{" "}
{method.maskedAccountNumber || "****"}
</div>
<div>
<span class="font-medium">Routing:</span>{" "}
{method.maskedRoutingNumber || "****"}
</div>
</div>
</div>
<div class="flex items-center gap-2 ml-4">
{!method.is_default && (
<button
type="button"
onClick={() => handleSetDefault(method.id!)}
class="text-blue-600 hover:text-blue-700 text-sm font-medium px-3 py-1.5 rounded border border-blue-600 hover:bg-blue-50 transition-colors"
>
Set Default
</button>
)}
<form
method="POST"
action="/api/delete/payment_method"
class="inline"
>
<input type="hidden" name="id" value={method.id} />
<input
type="hidden"
name="sender"
value={typeof location !== "undefined"
? location.pathname
: ""}
/>
<button
type="submit"
aria-label="Delete payment method"
class="text-red-600 hover:text-red-700 p-2 rounded hover:bg-red-50 transition-colors"
title="Delete payment method"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</button>
</form>
</div>
</div>
</li>
))}
</ul>
<div class="mt-6">
<button
type="button"
onClick={() => _setIsOpeningModal(true)}
class="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-6 rounded-lg shadow transition-colors flex items-center justify-center gap-2"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 4v16m8-8H4"
/>
</svg>
Add Payment Method
</button>
</div>
</>
)}
</div>
</>
);

View File

@ -51,8 +51,10 @@ export default function AddPaymentMethodDialog(
const formData = new FormData(formRef.current);
const bankName = formData.get("bank_name")?.toString().trim() || "";
const accountType = formData.get("account_type")?.toString() || "";
const routingNumber = formData.get("routing_number")?.toString().trim() || "";
const accountNumber = formData.get("account_number")?.toString().trim() || "";
const routingNumber = formData.get("routing_number")?.toString().trim() ||
"";
const accountNumber = formData.get("account_number")?.toString().trim() ||
"";
const isDefault = formData.get("is_default") === "true";
const sender = typeof location !== "undefined" ? location.pathname : "/";
@ -64,8 +66,10 @@ export default function AddPaymentMethodDialog(
};
setFieldErrors(validation);
if (validation.bank_name || validation.account_type ||
validation.routing_number || validation.account_number) {
if (
validation.bank_name || validation.account_type ||
validation.routing_number || validation.account_number
) {
return;
}

View File

@ -201,5 +201,3 @@ if (isAppReady) {
// if (import.meta.main) {
// await app.listen();
// }

View File

@ -90,4 +90,3 @@ export const handler = define.handlers({
}
},
});

View File

@ -38,7 +38,9 @@ export const handler = define.handlers({
<div class="row"><div class="label">Lease ID</div><div class="value">${leaseId}</div></div>
<div class="row"><div class="label">Amount</div><div class="value">$${amount.toLocaleString()}</div></div>
<div class="row"><div class="label">Method</div><div class="value">${method}</div></div>
<div class="row"><div class="label">Date</div><div class="value">${new Date(date).toLocaleString()}</div></div>
<div class="row"><div class="label">Date</div><div class="value">${
new Date(date).toLocaleString()
}</div></div>
</div>
</body>
</html>`;
@ -49,4 +51,3 @@ export const handler = define.handlers({
});
},
});

View File

@ -43,20 +43,3 @@ export const handler = define.handlers({
}
},
});

View File

@ -282,4 +282,3 @@ export default define.page(function LandlordPayments({ data }) {
</div>
);
});

View File

@ -150,40 +150,3 @@ export default define.page(function InviteTenantPage({ data }) {
</div>
);
});

View File

@ -21,9 +21,7 @@ export default define.page(function RentConfirmation({ data }) {
<h1 class="text-2xl font-bold text-green-700 mb-2">
Payment Successful
</h1>
{amount && (
<p class="text-gray-700 mb-4">Amount: ${amount}</p>
)}
{amount && <p class="text-gray-700 mb-4">Amount: ${amount}</p>}
<p class="text-gray-600 mb-6">
A receipt is available from your payment history.
</p>
@ -55,4 +53,3 @@ export default define.page(function RentConfirmation({ data }) {
</div>
);
});

View File

@ -387,4 +387,3 @@ export async function cancelAutoPayment(
.where(eq(leases.id, lease_id))
.returning();
}

View File

@ -592,4 +592,3 @@ export async function upsertAccessToken(tokenResponse: AccessTokenResponse) {
tokenResponse,
);
}