Added explicit return statements after redirect calls in all server actions to satisfy TypeScript type checking. These returns won't be reached due to redirects but are needed for type safety. Fixed in: - userProfileActions.ts (updateUserProfile) - locationActions.ts (updateOrAddLocation, deleteLocationById) - billActions.ts (updateOrAddBill, deleteBill) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
122 lines
3.5 KiB
TypeScript
122 lines
3.5 KiB
TypeScript
'use server';
|
|
|
|
import { z } from 'zod';
|
|
import { getDbClient } from '../dbClient';
|
|
import { UserProfile } from '../db-types';
|
|
import { withUser } from '@/app/lib/auth';
|
|
import { AuthenticatedUser } from '../types/next-auth';
|
|
import { unstable_noStore as noStore } from 'next/cache';
|
|
import { IntlTemplateFn } from '@/app/i18n';
|
|
import { getTranslations, getLocale } from "next-intl/server";
|
|
import { revalidatePath } from 'next/cache';
|
|
import { gotoHomeWithMessage } from './navigationActions';
|
|
import * as IBAN from 'iban';
|
|
|
|
export type State = {
|
|
errors?: {
|
|
firstName?: string[];
|
|
lastName?: string[];
|
|
address?: string[];
|
|
iban?: string[];
|
|
};
|
|
message?: string | null;
|
|
success?: boolean;
|
|
};
|
|
|
|
/**
|
|
* Schema for validating user profile form fields
|
|
*/
|
|
const FormSchema = (t: IntlTemplateFn) => z.object({
|
|
firstName: z.string().optional(),
|
|
lastName: z.string().optional(),
|
|
address: z.string().optional(),
|
|
iban: z.string()
|
|
.optional()
|
|
.refine(
|
|
(val) => {
|
|
if (!val || val.trim() === '') return true;
|
|
// Remove spaces and validate using iban.js library
|
|
const cleaned = val.replace(/\s/g, '').toUpperCase();
|
|
return IBAN.isValid(cleaned);
|
|
},
|
|
{ message: t("iban-invalid") }
|
|
),
|
|
});
|
|
|
|
/**
|
|
* Get user profile
|
|
*/
|
|
export const getUserProfile = withUser(async (user: AuthenticatedUser) => {
|
|
noStore();
|
|
|
|
const dbClient = await getDbClient();
|
|
const { id: userId } = user;
|
|
|
|
const profile = await dbClient.collection<UserProfile>("users")
|
|
.findOne({ userId });
|
|
|
|
return profile;
|
|
});
|
|
|
|
/**
|
|
* Update user profile
|
|
*/
|
|
export const updateUserProfile = withUser(async (user: AuthenticatedUser, prevState: State, formData: FormData) => {
|
|
noStore();
|
|
|
|
const t = await getTranslations("account-form.validation");
|
|
|
|
const validatedFields = FormSchema(t).safeParse({
|
|
firstName: formData.get('firstName') || undefined,
|
|
lastName: formData.get('lastName') || undefined,
|
|
address: formData.get('address') || undefined,
|
|
iban: formData.get('iban') || undefined,
|
|
});
|
|
|
|
// If form validation fails, return errors early. Otherwise, continue...
|
|
if (!validatedFields.success) {
|
|
return {
|
|
errors: validatedFields.error.flatten().fieldErrors,
|
|
message: t("validation-failed"),
|
|
success: false,
|
|
};
|
|
}
|
|
|
|
const { firstName, lastName, address, iban } = validatedFields.data;
|
|
|
|
// Normalize IBAN: remove spaces and convert to uppercase
|
|
const normalizedIban = iban ? iban.replace(/\s/g, '').toUpperCase() : null;
|
|
|
|
// Update the user profile in MongoDB
|
|
const dbClient = await getDbClient();
|
|
const { id: userId } = user;
|
|
|
|
const userProfile: UserProfile = {
|
|
userId,
|
|
firstName: firstName || null,
|
|
lastName: lastName || null,
|
|
address: address || null,
|
|
iban: normalizedIban,
|
|
};
|
|
|
|
await dbClient.collection<UserProfile>("users")
|
|
.updateOne(
|
|
{ userId },
|
|
{ $set: userProfile },
|
|
{ upsert: true }
|
|
);
|
|
|
|
revalidatePath('/account');
|
|
|
|
// Get current locale and redirect to home with success message
|
|
const locale = await getLocale();
|
|
await gotoHomeWithMessage(locale, 'profileSaved');
|
|
|
|
// This return is needed for TypeScript, but won't be reached due to redirect
|
|
return {
|
|
message: null,
|
|
errors: {},
|
|
success: true,
|
|
};
|
|
});
|