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:
@@ -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)
|
||||
})
|
||||
@@ -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
|
||||
|
||||
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:
|
||||
|
||||
// return(Promise.resolve(session));
|
||||
const session:Session = {
|
||||
user: {
|
||||
id: "109754742613069927799",
|
||||
name: "Nikola Derežić",
|
||||
},
|
||||
expires: "123",
|
||||
};
|
||||
|
||||
return(Promise.resolve(session));
|
||||
*/
|
||||
|
||||
return(auth());
|
||||
}
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user