feat: add city/state/country to complex, new settings page with sidebar, and Biome linting

- Added city, state, and country optional fields to Complex model
- Updated onboarding to include optional location fields
- Created new settings page with sidebar navigation (Datos del Complejo, Canchas)
- Replaced ESLint with Biome for frontend and backend linting
- Added parallel dev script with concurrently
- Migrated register-routes to use direct app.route() pattern
This commit is contained in:
Jose Selesan
2026-04-10 15:36:15 -03:00
parent 77004b14b0
commit 9ee98a4cb4
129 changed files with 2929 additions and 3186 deletions

View File

@@ -1,15 +1,15 @@
import { v7 as uuidv7 } from 'uuid'
import { Prisma } from '@/generated/prisma/client'
import { db } from '@/lib/prisma'
import { Prisma } from '@/generated/prisma/client';
import { db } from '@/lib/prisma';
import { v7 as uuidv7 } from 'uuid';
export type CreateSportInput = {
name: string
}
name: string;
};
export type UpdateSportInput = {
name?: string
isActive?: boolean
}
name?: string;
isActive?: boolean;
};
function slugify(value: string): string {
return value
@@ -19,18 +19,15 @@ function slugify(value: string): string {
.trim()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.replace(/-+/g, '-');
}
async function buildUniqueSlug(
source: string,
excludeSportId?: string,
): Promise<string> {
const base = slugify(source)
const fallback = base.length > 0 ? base : `sport-${uuidv7().slice(0, 8)}`
async function buildUniqueSlug(source: string, excludeSportId?: string): Promise<string> {
const base = slugify(source);
const fallback = base.length > 0 ? base : `sport-${uuidv7().slice(0, 8)}`;
let candidate = fallback
let index = 1
let candidate = fallback;
let index = 1;
while (true) {
const existing = await db.sport.findFirst({
@@ -45,23 +42,23 @@ async function buildUniqueSlug(
: {}),
},
select: { id: true },
})
});
if (!existing) return candidate
if (!existing) return candidate;
index += 1
candidate = `${fallback}-${index}`
index += 1;
candidate = `${fallback}-${index}`;
}
}
export async function listSports() {
return db.sport.findMany({
orderBy: { name: 'asc' },
})
});
}
export async function createSport(input: CreateSportInput) {
const slug = await buildUniqueSlug(input.name)
const slug = await buildUniqueSlug(input.name);
return db.sport.create({
data: {
@@ -70,27 +67,27 @@ export async function createSport(input: CreateSportInput) {
slug,
isActive: true,
},
})
});
}
export async function getSportById(id: string) {
return db.sport.findUnique({ where: { id } })
return db.sport.findUnique({ where: { id } });
}
export async function updateSport(id: string, input: UpdateSportInput) {
const data: Prisma.SportUncheckedUpdateInput = {}
const data: Prisma.SportUncheckedUpdateInput = {};
if (input.name) {
data.name = input.name
data.slug = await buildUniqueSlug(input.name, id)
data.name = input.name;
data.slug = await buildUniqueSlug(input.name, id);
}
if (input.isActive !== undefined) {
data.isActive = input.isActive
data.isActive = input.isActive;
}
return db.sport.update({
where: { id },
data,
})
});
}