This commit is contained in:
Nathan Anderson 2026-01-29 11:27:15 -06:00
parent 0e81e1fb3e
commit a5886eb01e
11 changed files with 58 additions and 16 deletions

View File

@ -215,6 +215,7 @@ export interface TenantInvite {
id: string;
landlord_id?: string | null;
property_id?: string | null;
lease_id?: string | null;
available_on?: number | null;
invited_emails?: string | null;
created_on?: number | null;

View File

@ -836,7 +836,7 @@ export class KvCacheStore {
case "roles": {
const roles = await sqlGetAllRoles();
const role = roles.find((r: { id: string; description: string }) => r.id === id);
const role = roles.find((r: { id: string; description: string | null }) => r.id === id);
if (!role) return null;
return {
id: role.id,
@ -847,8 +847,8 @@ export class KvCacheStore {
case "user_roles": {
const roles = await sqlGetUserRoles(id as string);
if (!roles || roles.length === 0) return null;
return roles.map((r: { roleId: string }) => r.roleId).filter((r: { roleId: string }) =>
r.roleId !== ""
return roles.map((r: { roleId: string | null }) => r.roleId).filter((roleId: string | null) =>
roleId !== ""
) as T;
}

View File

@ -81,7 +81,7 @@ export const handler = define.handlers({
stateData,
dashboardData: {
...dashboardData,
pendingLeaseApprovals,
pendingApprovals,
},
});
} catch (error) {

View File

@ -25,7 +25,7 @@ export const handler = define.handlers({
}
try {
const application = await getApplicationById(applicationId);
const application = await getApplicationById(applicationId) as TenantApplication | null;
if (!application || application.applicant_id !== user_id) {
return page<ApplicationDetailPageData>({
@ -48,7 +48,7 @@ export const handler = define.handlers({
if (application.document_urls_json) {
try {
documentUrls = JSON.parse(application.document_urls_json as string);
documentUrls = JSON.parse(application.document_urls_json as unknown as string);
} catch (e) {
console.error("Failed to parse document URLs:", e);
}

View File

@ -22,7 +22,7 @@ export const handler = define.handlers({
}
try {
const applications = await getApplicationsByApplicant(user_id);
const applications = await getApplicationsByApplicant(user_id) as TenantApplication[];
return page<ApplicationsPageData>({
applications: applications || [],

View File

@ -72,7 +72,7 @@ function MessageBubble(
const attachments = Array.isArray(message.attachments_json)
? message.attachments_json
: message.attachments_json
? JSON.parse(message.attachments_json as string)
? JSON.parse(message.attachments_json as unknown as string)
: [];
const content = message.content_encrypted || message.content || "";

View File

@ -220,7 +220,7 @@ export function addE2EMessage(
content,
content_encrypted: content,
parent_message_id: parentMessageId,
attachments_json: attachmentsJson,
attachments_json: attachmentsJson ? JSON.parse(attachmentsJson) as Record<string, unknown> : null,
is_read: false,
created_on: BASE_TIME,
};
@ -927,6 +927,7 @@ export function getE2ETenantApplicationsByLandlord(landlordId: string) {
application_notes: "Strong rental history.",
status: app.application_status || "pending",
created_at: app.submitted_on,
document_urls_json: app.document_urls_json ? JSON.stringify(app.document_urls_json) : null,
};
});
}
@ -949,7 +950,7 @@ export function createE2ETenantApplication(
applicant_id: applicantId,
application_status: "pending",
application_data_encrypted: applicationData,
document_urls_json: documentUrlsJson,
document_urls_json: documentUrlsJson ? JSON.parse(documentUrlsJson) as Record<string, unknown> : null,
submitted_on: BASE_TIME,
reviewed_on: null,
};
@ -1221,3 +1222,35 @@ export function getE2ELandlordDashboardData(userId: string) {
monthlyRevenue,
};
}
export function getE2EPendingApprovals() {
return e2eLeases.filter((lease) =>
lease.approval_status === "pending" || lease.approval_status === "requested"
);
}
export function addE2ELeaseWithApproval(
propertyId: string,
tenantId: string,
ownerId: string,
approvalStatus: string = "pending",
) {
const newLease: Lease = {
id: crypto.randomUUID(),
property_id: propertyId,
property_address: getE2EPropertyById(propertyId)?.address_1 || "",
tenant_id: tenantId,
owner_id: ownerId,
start_date: BASE_TIME + 1000 * 60 * 60 * 24 * 7,
end_date: BASE_TIME + 1000 * 60 * 60 * 24 * 377,
rent: 2000,
security_deposit: 2000,
lease_status: "draft",
approval_status: approvalStatus,
approval_requested_at: approvalStatus === "pending" ? BASE_TIME : null,
created_on: BASE_TIME,
updated_on: BASE_TIME,
};
e2eLeases = [newLease, ...e2eLeases];
return newLease;
}

View File

@ -216,7 +216,7 @@ export async function getPendingLeaseApprovals(
landlord_id: string,
) {
if (isE2EEnabled()) {
return getE2EPendingApprovals(landlord_id);
return getE2EPendingApprovals();
}
const pendingLeases = await db.select()
@ -311,7 +311,7 @@ export async function getLandlordDashboardData(
// In a real implementation, you'd use an IN clause
// For now, we'll get all applications and filter
applicationsResult = await db.select()
.from(tenant_applications);
.from(tenant_applications) as TenantApplication[];
applicationsResult = applicationsResult.filter((app) =>
app.property_id && property_ids.includes(app.property_id)

View File

@ -434,7 +434,7 @@ export async function rejectLease(
// Get pending lease approvals for a landlord
export async function getPendingApprovals(landlord_id: string) {
if (isE2EEnabled()) {
return getE2EPendingApprovals(landlord_id);
return getE2EPendingApprovals();
}
return await db.select()

View File

@ -18,7 +18,7 @@ export interface TenantApplication {
applicant_id?: string | null;
application_status?: string | null; // 'pending', 'approved', 'rejected'
application_data_encrypted?: string | null; // Encrypted application details
document_urls_json?: string | null;
document_urls_json?: Record<string, unknown> | null;
submitted_on?: number | null;
reviewed_on?: number | null;
}
@ -49,7 +49,14 @@ export interface ApplicationData {
}
// Extended interface for dashboard tenant applications with UI properties
export interface DashboardTenantApplication extends TenantApplication {
export interface DashboardTenantApplication {
id: string;
property_id?: string | null;
applicant_id?: string | null;
application_status?: string | null;
application_data_encrypted?: string | null;
submitted_on?: number | null;
reviewed_on?: number | null;
applicant_name?: string;
applicant_email?: string;
property_address?: string;
@ -57,6 +64,7 @@ export interface DashboardTenantApplication extends TenantApplication {
application_notes?: string;
status?: string; // UI-friendly status (maps to application_status)
created_at?: number | null; // UI-friendly timestamp (maps to submitted_on)
document_urls_json?: string | null; // UI-friendly string representation
}
// Create new tenant application

View File

@ -37,7 +37,7 @@ export async function isCreateTokenValid(
tokenId: string,
stateId: string,
): Promise<WebToken | null> {
const token = await sqlGetWebToken(tokenId);
const token = await sqlGetWebToken(tokenId) as WebToken | null;
const now = Date.now();
if (