feat(users): support creating app users with a Firebase Auth account

New users can now be created with a password, which creates a real
Firebase Auth account (so they can log into the mobile app immediately)
alongside the Firestore profile document. UserCreate is now
UserProfile + password (request-only, never persisted or echoed back);
deleting a user also removes their Auth account.

- backend/users: split UserCreate into UserProfile (persisted shape)
  and UserCreate (adds password), wire firebase_auth create/delete
- CreateUserModal: new lightweight modal for creating a user from
  other flows (e.g. device onboarding) without leaving the page
- UserForm: adds the password field for new users; also fixes
  useToast() being used undestructured (toast.success(...) was being
  called on the hook's return value instead of its .toast method)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-21 18:31:37 +03:00
co-authored by Claude Sonnet 5
parent 6e0a291228
commit 0d79a9f72c
4 changed files with 147 additions and 10 deletions
@@ -71,7 +71,7 @@ function StatusToggle({ value, onChange }) {
function PhotoField({ value, onChange, userId }) {
const fileInputRef = useRef(null)
const toast = useToast()
const { toast } = useToast()
const [uploading, setUploading] = useState(false)
const [hovered, setHovered] = useState(false)
@@ -192,7 +192,7 @@ function EyeToggle({ show, onToggle }) {
}
function PasswordCard({ userId, hasUid }) {
const toast = useToast()
const { toast } = useToast()
const [password, setPassword] = useState('')
const [confirm, setConfirm] = useState('')
const [showPass, setShowPass] = useState(false)
@@ -302,9 +302,9 @@ function PasswordCard({ userId, hasUid }) {
// ─── Main ────────────────────────────────────────────────────────────────────
export default function UserForm() {
const { id } = useParams()
const navigate = useNavigate()
const toast = useToast()
const { id } = useParams()
const navigate = useNavigate()
const { toast } = useToast()
const isEdit = Boolean(id)
const [form, setForm] = useState({
@@ -317,6 +317,7 @@ export default function UserForm() {
userTitle: '',
settingsPIN: '',
quickSettingsPIN: '',
password: '',
})
const [uid, setUid] = useState('')
const [loading, setLoading] = useState(false)
@@ -435,6 +436,18 @@ export default function UserForm() {
placeholder="+1 234 567 8900"
/>
</div>
{!isEdit && (
<FormField
label="Password"
name="password"
type="password"
value={form.password}
onChange={set('password')}
required
placeholder="Min. 6 characters"
hint="Used to sign into the mobile app immediately — this creates the Firebase Auth account."
/>
)}
<StatusToggle value={form.status} onChange={setVal('status')} />
</div>
</Card>