UX/UI improvements.
This commit is contained in:
parent
418d3cc402
commit
4e6f5d36b8
14 changed files with 1964 additions and 924 deletions
|
|
@ -1,66 +1,90 @@
|
|||
import mongoose from 'mongoose'
|
||||
import Event from '../server/models/event.js'
|
||||
import { connectDB } from '../server/utils/mongoose.js'
|
||||
import mongoose from "mongoose";
|
||||
import dotenv from "dotenv";
|
||||
import { connectDB } from "../server/utils/mongoose.js";
|
||||
import Event from "../server/models/event.js";
|
||||
|
||||
// Generate slug from title
|
||||
function generateSlug(title) {
|
||||
return title
|
||||
dotenv.config();
|
||||
|
||||
function generateSlug(title, startDate) {
|
||||
const titleSlug = title
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '')
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "");
|
||||
|
||||
if (startDate) {
|
||||
const d = new Date(startDate);
|
||||
const year = d.getUTCFullYear();
|
||||
const month = String(d.getUTCMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getUTCDate()).padStart(2, "0");
|
||||
return `${year}-${month}-${day}-${titleSlug}`;
|
||||
}
|
||||
|
||||
return titleSlug;
|
||||
}
|
||||
|
||||
async function migrateEventSlugs() {
|
||||
try {
|
||||
// Connect to database
|
||||
await connectDB()
|
||||
console.log('Connected to database')
|
||||
await connectDB();
|
||||
console.log("Connected to database\n");
|
||||
|
||||
// Find all events without slugs
|
||||
const eventsWithoutSlugs = await Event.find({
|
||||
$or: [
|
||||
{ slug: { $exists: false } },
|
||||
{ slug: null },
|
||||
{ slug: '' }
|
||||
]
|
||||
})
|
||||
const events = await Event.find({}).sort({ startDate: 1 }).lean();
|
||||
console.log(`Found ${events.length} event(s) to process\n`);
|
||||
|
||||
console.log(`Found ${eventsWithoutSlugs.length} events without slugs`)
|
||||
|
||||
if (eventsWithoutSlugs.length === 0) {
|
||||
console.log('All events already have slugs!')
|
||||
return
|
||||
if (events.length === 0) {
|
||||
console.log("No events found.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate and assign unique slugs
|
||||
for (const event of eventsWithoutSlugs) {
|
||||
let baseSlug = generateSlug(event.title)
|
||||
let slug = baseSlug
|
||||
let counter = 1
|
||||
// Build new slugs first so uniqueness checks don't conflict with slugs
|
||||
// we're about to replace in the same run.
|
||||
const updates = [];
|
||||
const usedSlugs = new Set();
|
||||
|
||||
// Ensure slug is unique
|
||||
while (await Event.findOne({ slug, _id: { $ne: event._id } })) {
|
||||
slug = `${baseSlug}-${counter}`
|
||||
counter++
|
||||
for (const event of events) {
|
||||
let baseSlug = generateSlug(event.title, event.startDate);
|
||||
let slug = baseSlug;
|
||||
let counter = 1;
|
||||
|
||||
// Ensure slug is unique within this batch and across the DB
|
||||
// (excluding the current event's own existing slug)
|
||||
while (
|
||||
usedSlugs.has(slug) ||
|
||||
(await Event.findOne({ slug, _id: { $ne: event._id } }).lean())
|
||||
) {
|
||||
slug = `${baseSlug}-${counter}`;
|
||||
counter++;
|
||||
}
|
||||
|
||||
event.slug = slug
|
||||
await event.save({ validateBeforeSave: false }) // Skip validation to avoid pre-save hook
|
||||
console.log(`✓ Generated slug "${slug}" for event "${event.title}"`)
|
||||
usedSlugs.add(slug);
|
||||
updates.push({ event, oldSlug: event.slug, newSlug: slug });
|
||||
}
|
||||
|
||||
console.log(`Successfully migrated ${eventsWithoutSlugs.length} events!`)
|
||||
// Apply updates
|
||||
let changed = 0;
|
||||
let skipped = 0;
|
||||
|
||||
for (const { event, oldSlug, newSlug } of updates) {
|
||||
if (oldSlug === newSlug) {
|
||||
console.log(` — ${event.title}`);
|
||||
console.log(` slug unchanged: ${newSlug}`);
|
||||
skipped++;
|
||||
} else {
|
||||
// Use updateOne to bypass the pre-save hook (avoids re-triggering slug generation)
|
||||
await Event.updateOne({ _id: event._id }, { $set: { slug: newSlug } });
|
||||
console.log(` ✓ ${event.title}`);
|
||||
console.log(` ${oldSlug || "(none)"} → ${newSlug}`);
|
||||
changed++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nDone. ${changed} updated, ${skipped} already correct.`);
|
||||
} catch (error) {
|
||||
console.error('Error migrating event slugs:', error)
|
||||
console.error("\nMigration failed:", error);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await mongoose.connection.close()
|
||||
console.log('Database connection closed')
|
||||
await mongoose.connection.close();
|
||||
console.log("Database connection closed.");
|
||||
}
|
||||
}
|
||||
|
||||
// Run migration if called directly
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
migrateEventSlugs()
|
||||
}
|
||||
|
||||
export default migrateEventSlugs
|
||||
migrateEventSlugs();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue