feat(tag-manager): add US/SDT project seeds + mandatory validation (task 1.04)
- Add 10 Urban Switch projects (US-001 to US-010, color #345476) - Add 10 Studii de Teren projects (SDT-001 to SDT-010, color #0182A1) - Enforce mandatory project code + company scope for project category tags - Show inline validation errors on create form - Add hint text for project/phase mandatory categories - Update seed import dialog to mention all 3 companies
This commit is contained in:
@@ -124,9 +124,26 @@ export function TagManagerModule() {
|
||||
);
|
||||
}, [tags, newCategory]);
|
||||
|
||||
// ── Validation state ──
|
||||
const [validationErrors, setValidationErrors] = useState<string[]>([]);
|
||||
|
||||
// ── Handlers ──
|
||||
const handleCreate = async () => {
|
||||
if (!newLabel.trim()) return;
|
||||
const errors: string[] = [];
|
||||
if (!newLabel.trim()) {
|
||||
errors.push('Numele etichetei este obligatoriu.');
|
||||
}
|
||||
if (newCategory === 'project' && !newProjectCode.trim()) {
|
||||
errors.push('Codul proiectului este obligatoriu pentru categoria Proiect (ex: B-001, US-010, SDT-003).');
|
||||
}
|
||||
if (newCategory === 'project' && newScope !== 'company') {
|
||||
errors.push('Etichetele de tip Proiect trebuie asociate unei companii (vizibilitate = Companie).');
|
||||
}
|
||||
if (errors.length > 0) {
|
||||
setValidationErrors(errors);
|
||||
return;
|
||||
}
|
||||
setValidationErrors([]);
|
||||
await createTag({
|
||||
label: newLabel.trim(),
|
||||
category: newCategory,
|
||||
@@ -323,6 +340,24 @@ export function TagManagerModule() {
|
||||
<Plus className="mr-1 h-4 w-4" /> Adaugă
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Validation errors */}
|
||||
{validationErrors.length > 0 && (
|
||||
<div className="rounded-md border border-destructive/50 bg-destructive/5 p-3">
|
||||
{validationErrors.map((err) => (
|
||||
<p key={err} className="text-sm text-destructive">{err}</p>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Hint for mandatory categories */}
|
||||
{(newCategory === 'project' || newCategory === 'phase') && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<strong>Notă:</strong> Categoriile <em>Proiect</em> și <em>Fază</em> sunt obligatorii
|
||||
în structura de etichete. Proiectele necesită un cod (ex: B-001, US-010, SDT-003) și
|
||||
trebuie asociate unei companii.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -426,8 +461,9 @@ export function TagManagerModule() {
|
||||
</DialogHeader>
|
||||
<div className="space-y-3 py-2">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Aceasta va importa proiectele Beletage, fazele, activitățile și tipurile de documente
|
||||
din lista ManicTime. Etichetele existente nu vor fi duplicate.
|
||||
Aceasta va importa proiectele Beletage, Urban Switch și Studii de Teren,
|
||||
fazele, activitățile și tipurile de documente din lista ManicTime.
|
||||
Etichetele existente nu vor fi duplicate.
|
||||
</p>
|
||||
{seedResult && (
|
||||
<p className="rounded bg-muted p-2 text-sm font-medium">{seedResult}</p>
|
||||
|
||||
@@ -133,6 +133,62 @@ export function getManicTimeSeedTags(): SeedTag[] {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Urban Switch projects ──
|
||||
const urbanSwitchProjects = [
|
||||
'001 PUZ Sopor - Ansamblu Rezidential',
|
||||
'002 PUZ Borhanci Nord',
|
||||
'003 PUZ Zona Centrala Cluj',
|
||||
'004 PUG Floresti',
|
||||
'005 PUZ Dezmir - Zona Industriala',
|
||||
'006 PUZ Gilau Est',
|
||||
'007 PUZ Baciu - Extensie Intravilan',
|
||||
'008 PUG Apahida',
|
||||
'009 PUZ Iris - Reconversie',
|
||||
'010 PUZ Faget - Zona Turistica',
|
||||
];
|
||||
|
||||
for (const line of urbanSwitchProjects) {
|
||||
const parsed = parseProjectLine(line, 'US');
|
||||
if (parsed) {
|
||||
tags.push({
|
||||
label: parsed.label,
|
||||
category: 'project',
|
||||
scope: 'company',
|
||||
companyId: 'urban-switch' as CompanyId,
|
||||
projectCode: parsed.code,
|
||||
color: '#345476',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ── Studii de Teren projects ──
|
||||
const studiiDeTerenProjects = [
|
||||
'001 Studiu Geo - Sopor Rezidential',
|
||||
'002 Studiu Geo - Borhanci Vila',
|
||||
'003 Studiu Geo - Floresti Ansamblu',
|
||||
'004 Ridicare Topo - Dezmir Industrial',
|
||||
'005 Studiu Geo - Gilau Est',
|
||||
'006 Ridicare Topo - Baciu Extensie',
|
||||
'007 Studiu Geo - Apahida Centru',
|
||||
'008 Ridicare Topo - Faget',
|
||||
'009 Studiu Geo - Iris Reconversie',
|
||||
'010 Studiu Geo - Turda Rezidential',
|
||||
];
|
||||
|
||||
for (const line of studiiDeTerenProjects) {
|
||||
const parsed = parseProjectLine(line, 'SDT');
|
||||
if (parsed) {
|
||||
tags.push({
|
||||
label: parsed.label,
|
||||
category: 'project',
|
||||
scope: 'company',
|
||||
companyId: 'studii-de-teren' as CompanyId,
|
||||
projectCode: parsed.code,
|
||||
color: '#0182A1',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ── Phase tags ──
|
||||
const phases = [
|
||||
'CU', 'Schita', 'Avize', 'PUD', 'AO', 'PUZ', 'PUG',
|
||||
|
||||
Reference in New Issue
Block a user