Add ESLint + Prettier + EditorConfig tooling at repo root

v1.0 Phase 1.1 — repo-wide lint/format baseline.

- eslint.config.mjs (flat config) lints server, client, shared
- .prettierrc.json, .prettierignore, .editorconfig, .nvmrc
- Root package.json holds shared devDeps; per-package scripts keep
  their typecheck + test runners
- Fix 7 lint issues surfaced by the baseline run:
  - TicketDetail.tsx: replace ternary-with-side-effects with if/else
  - admin/Users.tsx: escape apostrophe in JSX
  - errorHandler.ts: typed err as unknown with ErrorLike refinement
  - users.ts: Prisma.UserUpdateInput instead of Record<string, any>
  - seed.ts: drop unused goddard binding
- Run prettier across tracked sources for a clean formatting baseline
This commit is contained in:
2026-04-18 14:47:34 -04:00
parent 2a6090e473
commit 27d2ab0f0d
48 changed files with 14460 additions and 1096 deletions
+28 -28
View File
@@ -1,57 +1,57 @@
import { useEffect, useState } from 'react'
import api from '../api/client'
import { Category, CTIType, Item } from '../types'
import { useEffect, useState } from 'react';
import api from '../api/client';
import { Category, CTIType, Item } from '../types';
interface CTISelectProps {
value: { categoryId: string; typeId: string; itemId: string }
onChange: (value: { categoryId: string; typeId: string; itemId: string }) => void
disabled?: boolean
value: { categoryId: string; typeId: string; itemId: string };
onChange: (value: { categoryId: string; typeId: string; itemId: string }) => void;
disabled?: boolean;
}
export default function CTISelect({ value, onChange, disabled }: CTISelectProps) {
const [categories, setCategories] = useState<Category[]>([])
const [types, setTypes] = useState<CTIType[]>([])
const [items, setItems] = useState<Item[]>([])
const [categories, setCategories] = useState<Category[]>([]);
const [types, setTypes] = useState<CTIType[]>([]);
const [items, setItems] = useState<Item[]>([]);
useEffect(() => {
api.get<Category[]>('/cti/categories').then((r) => setCategories(r.data))
}, [])
api.get<Category[]>('/cti/categories').then((r) => setCategories(r.data));
}, []);
useEffect(() => {
if (!value.categoryId) {
setTypes([])
setItems([])
return
setTypes([]);
setItems([]);
return;
}
api
.get<CTIType[]>('/cti/types', { params: { categoryId: value.categoryId } })
.then((r) => setTypes(r.data))
}, [value.categoryId])
.then((r) => setTypes(r.data));
}, [value.categoryId]);
useEffect(() => {
if (!value.typeId) {
setItems([])
return
setItems([]);
return;
}
api
.get<Item[]>('/cti/items', { params: { typeId: value.typeId } })
.then((r) => setItems(r.data))
}, [value.typeId])
.then((r) => setItems(r.data));
}, [value.typeId]);
const handleCategory = (categoryId: string) => {
onChange({ categoryId, typeId: '', itemId: '' })
}
onChange({ categoryId, typeId: '', itemId: '' });
};
const handleType = (typeId: string) => {
onChange({ ...value, typeId, itemId: '' })
}
onChange({ ...value, typeId, itemId: '' });
};
const handleItem = (itemId: string) => {
onChange({ ...value, itemId })
}
onChange({ ...value, itemId });
};
const selectClass =
'block w-full bg-gray-800 border border-gray-700 text-gray-100 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed'
'block w-full bg-gray-800 border border-gray-700 text-gray-100 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed';
return (
<div className="grid grid-cols-3 gap-3">
@@ -106,5 +106,5 @@ export default function CTISelect({ value, onChange, disabled }: CTISelectProps)
</select>
</div>
</div>
)
);
}