'use server'; import { getDbClient } from '../dbClient'; import { BillingLocation, EmailStatus } from '../db-types'; import { extractShareId, validateShareChecksum } from '@evidencija-rezija/shared-code'; import { revalidatePath } from 'next/cache'; export type EmailActionResult = { success: boolean; message?: string; }; /** * Verify tenant email address * Updates the email status to Verified for the location and all subsequent matching locations * * @param shareId - The share ID from the verification link (locationId + checksum) * @returns Result indicating success or failure */ export async function verifyTenantEmail(shareId: string): Promise { // Extract and validate share ID const extracted = extractShareId(shareId); if (!extracted) { return { success: false, message: 'Invalid verification link' }; } const { locationId, checksum } = extracted; // Validate checksum if (!validateShareChecksum(locationId, checksum)) { return { success: false, message: 'Invalid verification link' }; } // Get database client const dbClient = await getDbClient(); // Fetch the location to get userId, name, tenantEmail, and yearMonth const location = await dbClient.collection("lokacije") .findOne( { _id: locationId }, { projection: { userId: 1, name: 1, tenantEmail: 1, yearMonth: 1 } } ); if (!location) { return { success: false, message: 'Location not found' }; } if (!location.tenantEmail) { return { success: false, message: 'No tenant email configured for this location' }; } // Update current and all subsequent matching locations // Match by: userId, name, tenantEmail, and yearMonth >= current const result = await dbClient.collection("lokacije").updateMany( { userId: location.userId, name: location.name, tenantEmail: location.tenantEmail, $or: [ { "yearMonth.year": { $gt: location.yearMonth.year } }, { "yearMonth.year": location.yearMonth.year, "yearMonth.month": { $gte: location.yearMonth.month } } ] }, { $set: { tenantEmailStatus: EmailStatus.Verified } } ); // Revalidate paths to refresh UI revalidatePath('/[locale]', 'layout'); return { success: true, message: `Email verified successfully (${result.modifiedCount} location(s) updated)` }; } /** * Unsubscribe tenant from email notifications * Updates the email status to Unsubscribed for the location and all subsequent matching locations * * @param shareId - The share ID from the unsubscribe link (locationId + checksum) * @returns Result indicating success or failure */ export async function unsubscribeTenantEmail(shareId: string): Promise { // Extract and validate share ID const extracted = extractShareId(shareId); if (!extracted) { return { success: false, message: 'Invalid unsubscribe link' }; } const { locationId, checksum } = extracted; // Validate checksum if (!validateShareChecksum(locationId, checksum)) { return { success: false, message: 'Invalid unsubscribe link' }; } // Get database client const dbClient = await getDbClient(); // Fetch the location to get userId, name, tenantEmail, and yearMonth const location = await dbClient.collection("lokacije") .findOne( { _id: locationId }, { projection: { userId: 1, name: 1, tenantEmail: 1, yearMonth: 1 } } ); if (!location) { return { success: false, message: 'Location not found' }; } if (!location.tenantEmail) { return { success: false, message: 'No tenant email configured for this location' }; } // Update current and all subsequent matching locations // Match by: userId, name, tenantEmail, and yearMonth >= current const result = await dbClient.collection("lokacije").updateMany( { userId: location.userId, name: location.name, tenantEmail: location.tenantEmail, $or: [ { "yearMonth.year": { $gt: location.yearMonth.year } }, { "yearMonth.year": location.yearMonth.year, "yearMonth.month": { $gte: location.yearMonth.month } } ] }, { $set: { tenantEmailStatus: EmailStatus.Unsubscribed } } ); // Revalidate paths to refresh UI revalidatePath('/[locale]', 'layout'); return { success: true, message: `Unsubscribed successfully (${result.modifiedCount} location(s) updated)` }; }