diff --git a/components/Onboarding.tsx b/components/Onboarding.tsx index 630608a..3ae7e7a 100644 --- a/components/Onboarding.tsx +++ b/components/Onboarding.tsx @@ -68,35 +68,38 @@ export function Onboarding({ onComplete }: Props) {
- + setPiFirstName(e.target.value)} - required placeholder="e.g. Smith" />
- + setBldgCode(e.target.value)} - required placeholder="e.g. EER" />
- + setLab(e.target.value)} - required placeholder="e.g. 3.822" />
diff --git a/server/src/db/schema.sql b/server/src/db/schema.sql index d514253..a8b5d2a 100644 --- a/server/src/db/schema.sql +++ b/server/src/db/schema.sql @@ -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; diff --git a/server/src/routes/profile.ts b/server/src/routes/profile.ts index 95103b9..c323c58 100644 --- a/server/src/routes/profile.ts +++ b/server/src/routes/profile.ts @@ -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 {