/// Mirrors `inviteResp` from internal/api/admin_invites.go. The list /// endpoint wraps these in `{"invites": [...]}`; the create endpoint /// returns a single bare invite. Envelope parsing is done in /// `AdminInvitesApi`, not here. /// /// `invitedBy` is the UUID of the inviting admin (not their username); /// the server doesn't currently denormalize it. Likewise `redeemedBy`. /// TTL is hardcoded server-side at 24h, so admins can't customise the /// expiry — only the optional `note`. class Invite { const Invite({ required this.token, required this.invitedBy, this.note, required this.createdAt, required this.expiresAt, this.redeemedAt, this.redeemedBy, }); final String token; final String invitedBy; final String? note; final String createdAt; final String expiresAt; final String? redeemedAt; final String? redeemedBy; bool get isRedeemed => redeemedAt != null; factory Invite.fromJson(Map j) => Invite( token: j['token'] as String? ?? '', invitedBy: j['invited_by'] as String? ?? '', note: j['note'] as String?, createdAt: j['created_at'] as String? ?? '', expiresAt: j['expires_at'] as String? ?? '', redeemedAt: j['redeemed_at'] as String?, redeemedBy: j['redeemed_by'] as String?, ); }