nullable fields
All checks were successful
Deploy to Server / deploy (push) Successful in 33s

This commit is contained in:
2026-04-10 20:08:35 -05:00
parent d1141a7b3a
commit 3ffea6a92b
3 changed files with 21 additions and 13 deletions

View File

@@ -68,35 +68,38 @@ export function Onboarding({ onComplete }: Props) {
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-1">
<Label htmlFor="pi">PI first name</Label>
<Label htmlFor="pi">
PI first name <span className="text-muted-foreground font-normal">(optional)</span>
</Label>
<Input
id="pi"
type="text"
value={piFirstName}
onChange={e => setPiFirstName(e.target.value)}
required
placeholder="e.g. Smith"
/>
</div>
<div className="space-y-1">
<Label htmlFor="bldg">Building code</Label>
<Label htmlFor="bldg">
Building code <span className="text-muted-foreground font-normal">(optional)</span>
</Label>
<Input
id="bldg"
type="text"
value={bldgCode}
onChange={e => setBldgCode(e.target.value)}
required
placeholder="e.g. EER"
/>
</div>
<div className="space-y-1">
<Label htmlFor="lab">Lab</Label>
<Label htmlFor="lab">
Lab <span className="text-muted-foreground font-normal">(optional)</span>
</Label>
<Input
id="lab"
type="text"
value={lab}
onChange={e => setLab(e.target.value)}
required
placeholder="e.g. 3.822"
/>
</div>

View File

@@ -112,10 +112,16 @@ CREATE INDEX IF NOT EXISTS protocols_user_id_idx ON protocols(user_id);
-- User profile — lab defaults pre-filled on chemical entries
CREATE TABLE IF NOT EXISTS user_profile (
user_id TEXT NOT NULL PRIMARY KEY REFERENCES "user"("id") ON DELETE CASCADE,
pi_first_name TEXT NOT NULL,
bldg_code TEXT NOT NULL,
lab TEXT NOT NULL,
pi_first_name TEXT,
bldg_code TEXT,
lab TEXT,
contact TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Allow existing deployments to have nullable profile fields.
-- DROP NOT NULL on an already-nullable column is a no-op in Postgres.
ALTER TABLE user_profile ALTER COLUMN pi_first_name DROP NOT NULL;
ALTER TABLE user_profile ALTER COLUMN bldg_code DROP NOT NULL;
ALTER TABLE user_profile ALTER COLUMN lab DROP NOT NULL;

View File

@@ -21,9 +21,8 @@ router.get('/', requireAuth, async (req, res) => {
router.post('/', requireAuth, async (req, res) => {
const { pi_first_name, bldg_code, lab, contact } = req.body;
if (!pi_first_name || !bldg_code || !lab) {
return res.status(400).json({ error: 'pi_first_name, bldg_code, and lab are required' });
}
// Coerce empty strings to null so the DB stores a clean null rather than "".
const toNull = (v: unknown) => (typeof v === 'string' && v.trim() !== '' ? v.trim() : null);
try {
const result = await pool.query(
`INSERT INTO user_profile (user_id, pi_first_name, bldg_code, lab, contact)
@@ -35,7 +34,7 @@ router.post('/', requireAuth, async (req, res) => {
contact = EXCLUDED.contact,
updated_at = NOW()
RETURNING *`,
[req.user!.id, pi_first_name, bldg_code, lab, contact || null]
[req.user!.id, toNull(pi_first_name), toNull(bldg_code), toNull(lab), toNull(contact)]
);
res.json(result.rows[0]);
} catch {