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
+32 -32
View File
@@ -1,19 +1,19 @@
import { useState, useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import api from '../api/client'
import Modal from '../components/Modal'
import CTISelect from '../components/CTISelect'
import { User } from '../types'
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import api from '../api/client';
import Modal from '../components/Modal';
import CTISelect from '../components/CTISelect';
import { User } from '../types';
interface NewTicketModalProps {
onClose: () => void
onClose: () => void;
}
export default function NewTicketModal({ onClose }: NewTicketModalProps) {
const navigate = useNavigate()
const [users, setUsers] = useState<User[]>([])
const [error, setError] = useState('')
const [submitting, setSubmitting] = useState(false)
const navigate = useNavigate();
const [users, setUsers] = useState<User[]>([]);
const [error, setError] = useState('');
const [submitting, setSubmitting] = useState(false);
const [form, setForm] = useState({
title: '',
@@ -23,24 +23,24 @@ export default function NewTicketModal({ onClose }: NewTicketModalProps) {
categoryId: '',
typeId: '',
itemId: '',
})
});
useEffect(() => {
api.get<User[]>('/users').then((r) => setUsers(r.data))
}, [])
api.get<User[]>('/users').then((r) => setUsers(r.data));
}, []);
const handleCTI = (cti: { categoryId: string; typeId: string; itemId: string }) => {
setForm((f) => ({ ...f, ...cti }))
}
setForm((f) => ({ ...f, ...cti }));
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
e.preventDefault();
if (!form.categoryId || !form.typeId || !form.itemId) {
setError('Please select a Category, Type, and Item')
return
setError('Please select a Category, Type, and Item');
return;
}
setError('')
setSubmitting(true)
setError('');
setSubmitting(true);
try {
const payload: Record<string, unknown> = {
title: form.title,
@@ -49,22 +49,22 @@ export default function NewTicketModal({ onClose }: NewTicketModalProps) {
categoryId: form.categoryId,
typeId: form.typeId,
itemId: form.itemId,
}
if (form.assigneeId) payload.assigneeId = form.assigneeId
};
if (form.assigneeId) payload.assigneeId = form.assigneeId;
const res = await api.post('/tickets', payload)
onClose()
navigate(`/${res.data.displayId}`)
const res = await api.post('/tickets', payload);
onClose();
navigate(`/${res.data.displayId}`);
} catch {
setError('Failed to create ticket')
setError('Failed to create ticket');
} finally {
setSubmitting(false)
setSubmitting(false);
}
}
};
const inputClass =
'w-full bg-gray-800 border border-gray-700 text-gray-100 placeholder-gray-500 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent'
const labelClass = 'block text-sm font-medium text-gray-300 mb-1'
'w-full bg-gray-800 border border-gray-700 text-gray-100 placeholder-gray-500 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent';
const labelClass = 'block text-sm font-medium text-gray-300 mb-1';
return (
<Modal title="New Ticket" onClose={onClose} size="lg">
@@ -161,5 +161,5 @@ export default function NewTicketModal({ onClose }: NewTicketModalProps) {
</div>
</form>
</Modal>
)
);
}