diff --git a/server/src/entities/orgs/handlers/invites/add-invite.ts b/server/src/entities/orgs/handlers/invites/add-invite.ts index ed530a2..010e8c1 100644 --- a/server/src/entities/orgs/handlers/invites/add-invite.ts +++ b/server/src/entities/orgs/handlers/invites/add-invite.ts @@ -25,6 +25,14 @@ const validators = [ })), ]; +/** + * Ensure that the construction of these URLs is done + * in exactly one place only. + */ +export function inviteUrl(invite: Invite): string { + return `${env.MELI_URL}/invite?token=${invite.token}`; +} + async function handler(req: Request, res: Response): Promise { const { orgId } = req.params; const { email, admin } = req.body; @@ -53,7 +61,7 @@ async function handler(req: Request, res: Response): Promise { await sendInvite(email, { org: org.name, - url: `${env.MELI_URL}/invite?token=${invite.token}`, + url: inviteUrl(invite), }); emitEvent(EventType.org_invite_added, { diff --git a/server/src/entities/orgs/serialize-invite.ts b/server/src/entities/orgs/serialize-invite.ts index aa07585..ca45ae4 100644 --- a/server/src/entities/orgs/serialize-invite.ts +++ b/server/src/entities/orgs/serialize-invite.ts @@ -1,3 +1,4 @@ +import { inviteUrl } from './handlers/invites/add-invite'; import { Invite } from './invite'; export function serializeInvite(invite: Invite) { @@ -5,6 +6,7 @@ export function serializeInvite(invite: Invite) { _id: invite._id, email: invite.email, expiresAt: invite.expiresAt, + url: inviteUrl(invite), memberOptions: invite.memberOptions, }; } diff --git a/ui/src/components/orgs/staff/invites/InviteView.tsx b/ui/src/components/orgs/staff/invites/InviteView.tsx index 11b37fb..aa896ef 100644 --- a/ui/src/components/orgs/staff/invites/InviteView.tsx +++ b/ui/src/components/orgs/staff/invites/InviteView.tsx @@ -1,12 +1,15 @@ -import React from 'react'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faTimes } from '@fortawesome/free-solid-svg-icons'; -import { Invite } from './invite'; -import { DeleteInvite } from './DeleteInvite'; -import { FromNow } from '../../../../commons/components/FromNow'; -import { ButtonIcon } from '../../../../commons/components/ButtonIcon'; +import React from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faLink, faTimes } from "@fortawesome/free-solid-svg-icons"; +import { Invite } from "./invite"; +import { DeleteInvite } from "./DeleteInvite"; +import { FromNow } from "../../../../commons/components/FromNow"; +import { ButtonIcon } from "../../../../commons/components/ButtonIcon"; -export function InviteView({ invite, onDelete }: { +export function InviteView({ + invite, + onDelete, +}: { invite: Invite; onDelete: () => void; }) { @@ -15,6 +18,9 @@ export function InviteView({ invite, onDelete }: { return (
+ + + {" "} {invite.email} {invite.memberOptions.admin && ( admin @@ -23,14 +29,10 @@ export function InviteView({ invite, onDelete }: {
{expired ? ( -
- expired -
+
expired
) : ( <> -
- pending invitation -
+
pending invitation
)} diff --git a/ui/src/components/orgs/staff/invites/invite.ts b/ui/src/components/orgs/staff/invites/invite.ts index 386e991..7ca3486 100644 --- a/ui/src/components/orgs/staff/invites/invite.ts +++ b/ui/src/components/orgs/staff/invites/invite.ts @@ -2,6 +2,7 @@ export interface Invite { _id: string; email: string; expiresAt: Date; + url: string; memberOptions: { admin: boolean; };