add option to create location in all subsequent months

- Added toggle in LocationEditForm for adding locations to future months (disabled by default)
- Modified updateOrAddLocation action to support batch creation across subsequent months
- Only creates locations in months where no location with same name exists
- Added translations for toggle text in Croatian and English
- Fixed unused variable warning in deleteLocationById
- Improved auth.ts development comments for clarity

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-08-11 10:27:31 +02:00
parent eef93528e3
commit 78a6c18ba5
5 changed files with 112 additions and 10 deletions

View File

@@ -27,6 +27,7 @@ const FormSchema = (t:IntlTemplateFn) => z.object({
_id: z.string(),
locationName: z.coerce.string().min(1, t("location-name-required")),
locationNotes: z.string(),
addToSubsequentMonths: z.boolean().optional(),
})
// dont include the _id field in the response
.omit({ _id: true });
@@ -47,6 +48,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
const validatedFields = FormSchema(t).safeParse({
locationName: formData.get('locationName'),
locationNotes: formData.get('locationNotes'),
addToSubsequentMonths: formData.get('addToSubsequentMonths') === 'on',
});
// If form validation fails, return errors early. Otherwise, continue...
@@ -60,6 +62,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
const {
locationName,
locationNotes,
addToSubsequentMonths,
} = validatedFields.data;
// update the bill in the mongodb
@@ -80,6 +83,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
}
});
} else if(yearMonth) {
// Always add location to the specified month
await dbClient.collection<BillingLocation>("lokacije").insertOne({
_id: (new ObjectId()).toHexString(),
userId,
@@ -89,6 +93,78 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
yearMonth: yearMonth,
bills: [],
});
// If addToSubsequentMonths is enabled, add to all subsequent months
if (addToSubsequentMonths) {
// Find all subsequent months that exist in the database
const subsequentMonths = await dbClient.collection<BillingLocation>("lokacije")
.aggregate([
{
$match: {
userId,
$or: [
{ "yearMonth.year": { $gt: yearMonth.year } },
{
"yearMonth.year": yearMonth.year,
"yearMonth.month": { $gt: yearMonth.month }
}
]
}
},
{
$group: {
_id: {
year: "$yearMonth.year",
month: "$yearMonth.month"
}
}
},
{
$project: {
_id: 0,
year: "$_id.year",
month: "$_id.month"
}
},
{
$sort: {
year: 1,
month: 1
}
}
])
.toArray();
// For each subsequent month, check if location with same name already exists
const locationsToInsert = [];
for (const monthData of subsequentMonths) {
const existingLocation = await dbClient.collection<BillingLocation>("lokacije")
.findOne({
userId,
name: locationName,
"yearMonth.year": monthData.year,
"yearMonth.month": monthData.month
});
// Only add if location with same name doesn't already exist in that month
if (!existingLocation) {
locationsToInsert.push({
_id: (new ObjectId()).toHexString(),
userId,
userEmail,
name: locationName,
notes: locationNotes,
yearMonth: { year: monthData.year, month: monthData.month },
bills: [],
});
}
}
// Insert all new locations at once if any
if (locationsToInsert.length > 0) {
await dbClient.collection<BillingLocation>("lokacije").insertMany(locationsToInsert);
}
}
}
if(yearMonth) await gotoHome(yearMonth);
@@ -235,7 +311,7 @@ export const deleteLocationById = withUser(async (user:AuthenticatedUser, locati
const { id: userId } = user;
// find a location with the given locationID
const post = await dbClient.collection<BillingLocation>("lokacije").deleteOne({ _id: locationID, userId });
await dbClient.collection<BillingLocation>("lokacije").deleteOne({ _id: locationID, userId });
await gotoHome(yearMonth)
})

View File

@@ -7,17 +7,31 @@ import { defaultLocale } from '../i18n';
export const myAuth = () => {
// Ovo koristim u developmentu
/**
// const session:Session = {
// user: {
// id: "109754742613069927799",
// name: "Nikola Derežić",
// },
// expires: "123",
// };
Google auth does not work in development environment
- this is a hack to make it work in development environment
- it returns a fake session object which is used by the Next-Auth middleware
// return(Promise.resolve(session));
Instructions: when in dev environment, uncomment the following code snippet
- this will return a fake session object which is used by the Next-Auth middleware
- when in production environment, comment the code snippet back
Note: this is not a secure way to handle authentication, it is only for development purposes
- in production environment, the auth should be handled by the Next-Auth middleware
Code snippet:
const session:Session = {
user: {
id: "109754742613069927799",
name: "Nikola Derežić",
},
expires: "123",
};
return(Promise.resolve(session));
*/
return(auth());
}

View File

@@ -60,6 +60,16 @@ export const LocationEditForm:FC<LocationEditFormProps> = ({ location, yearMonth
))}
</div>
{/* Show toggle only when adding a new location (not editing) */}
{!location && (
<div className="form-control">
<label className="label cursor-pointer">
<span className="label-text">{t("add-to-subsequent-months")}</span>
<input type="checkbox" name="addToSubsequentMonths" className="toggle toggle-primary" />
</label>
</div>
)}
<div id="status-error" aria-live="polite" aria-atomic="true">
{
state.message &&

View File

@@ -98,6 +98,7 @@
"save-button": "Save",
"cancel-button": "Cancel",
"delete-tooltip": "Delete realestate",
"add-to-subsequent-months": "Add to all subsequent months",
"validation": {
"location-name-required": "Relaestate name is required"
}

View File

@@ -97,6 +97,7 @@
"save-button": "Spremi",
"cancel-button": "Odbaci",
"delete-tooltip": "Brisanje nekretnine",
"add-to-subsequent-months": "Dodaj u sve mjesece koji slijede",
"validation": {
"location-name-required": "Ime nekretnine je obavezno"
}