|
1 | 1 | import { useForm } from "@conform-to/react";
|
2 | 2 | import { parse } from "@conform-to/zod";
|
3 | 3 | import { EnvelopeIcon, LockOpenIcon, TrashIcon, UserPlusIcon } from "@heroicons/react/20/solid";
|
4 |
| -import { Form, MetaFunction, useActionData } from "@remix-run/react"; |
5 |
| -import { ActionFunction, LoaderFunctionArgs, json } from "@remix-run/server-runtime"; |
| 4 | +import { Form, type MetaFunction, useActionData } from "@remix-run/react"; |
| 5 | +import { type ActionFunction, type LoaderFunctionArgs, json } from "@remix-run/server-runtime"; |
6 | 6 | import { useState } from "react";
|
7 |
| -import { UseDataFunctionReturn, typedjson, useTypedLoaderData } from "remix-typedjson"; |
| 7 | +import { type UseDataFunctionReturn, typedjson, useTypedLoaderData } from "remix-typedjson"; |
8 | 8 | import invariant from "tiny-invariant";
|
9 | 9 | import { z } from "zod";
|
10 | 10 | import { UserAvatar } from "~/components/UserProfilePhoto";
|
11 | 11 | import { AdminDebugTooltip } from "~/components/admin/debugTooltip";
|
12 |
| -import { PageBody, PageContainer } from "~/components/layout/AppLayout"; |
| 12 | +import { |
| 13 | + MainHorizontallyCenteredContainer, |
| 14 | + PageBody, |
| 15 | + PageContainer, |
| 16 | +} from "~/components/layout/AppLayout"; |
13 | 17 | import {
|
14 | 18 | Alert,
|
15 | 19 | AlertCancel,
|
@@ -158,82 +162,88 @@ export default function Page() {
|
158 | 162 | </PageAccessories>
|
159 | 163 | </NavBar>
|
160 | 164 | <PageBody>
|
161 |
| - <Header2> |
162 |
| - Members ({limits.used}/{limits.limit}) |
163 |
| - </Header2> |
164 |
| - <ul className="divide-ui-border flex w-full max-w-md flex-col divide-y border-b border-grid-bright"> |
165 |
| - {members.map((member) => ( |
166 |
| - <li key={member.user.id} className="flex items-center gap-x-4 py-4"> |
167 |
| - <UserAvatar |
168 |
| - avatarUrl={member.user.avatarUrl} |
169 |
| - name={member.user.name} |
170 |
| - className="h-10 w-10" |
171 |
| - /> |
172 |
| - <div className="flex flex-col gap-0.5"> |
173 |
| - <Header3> |
174 |
| - {member.user.name}{" "} |
175 |
| - {member.user.id === user.id && <span className="text-text-dimmed">(You)</span>} |
176 |
| - </Header3> |
177 |
| - <Paragraph variant="small">{member.user.email}</Paragraph> |
178 |
| - </div> |
179 |
| - <div className="flex grow items-center justify-end gap-4"> |
180 |
| - <LeaveRemoveButton userId={user.id} member={member} memberCount={members.length} /> |
181 |
| - </div> |
182 |
| - </li> |
183 |
| - ))} |
184 |
| - </ul> |
185 |
| - |
186 |
| - {invites.length > 0 && ( |
187 |
| - <> |
188 |
| - <Header2 className="mt-4">Pending invites</Header2> |
189 |
| - <ul className="flex w-full max-w-md flex-col divide-y divide-charcoal-800 border-b border-charcoal-800"> |
190 |
| - {invites.map((invite) => ( |
191 |
| - <li key={invite.id} className="flex items-center gap-4 py-4"> |
192 |
| - <div className="rounded-md border border-charcoal-750 bg-charcoal-800 p-1.5"> |
193 |
| - <EnvelopeIcon className="size-7 text-cyan-500" /> |
194 |
| - </div> |
195 |
| - <div className="flex flex-col gap-0.5"> |
196 |
| - <Header3>{invite.email}</Header3> |
197 |
| - <Paragraph variant="small"> |
198 |
| - Invite sent {<DateTime date={invite.updatedAt} />} |
199 |
| - </Paragraph> |
200 |
| - </div> |
201 |
| - <div className="flex grow items-center justify-end gap-x-2"> |
202 |
| - <ResendButton invite={invite} /> |
203 |
| - <RevokeButton invite={invite} /> |
204 |
| - </div> |
205 |
| - </li> |
206 |
| - ))} |
207 |
| - </ul> |
208 |
| - </> |
209 |
| - )} |
210 |
| - |
211 |
| - {requiresUpgrade ? ( |
212 |
| - <InfoPanel |
213 |
| - variant="upgrade" |
214 |
| - icon={LockOpenIcon} |
215 |
| - iconClassName="text-indigo-500" |
216 |
| - title="Unlock more team members" |
217 |
| - to={v3BillingPath(organization)} |
218 |
| - buttonLabel="Upgrade" |
219 |
| - panelClassName="mt-4 max-w-sm" |
220 |
| - > |
221 |
| - <Paragraph variant="small"> |
222 |
| - You've used all {limits.limit} of your available team members. Upgrade your plan to |
223 |
| - enable more. |
224 |
| - </Paragraph> |
225 |
| - </InfoPanel> |
226 |
| - ) : ( |
227 |
| - <div className="mt-4 flex max-w-md justify-end"> |
228 |
| - <LinkButton |
229 |
| - to={inviteTeamMemberPath(organization)} |
230 |
| - variant={"primary/small"} |
231 |
| - LeadingIcon={UserPlusIcon} |
| 165 | + <MainHorizontallyCenteredContainer> |
| 166 | + <Header2> |
| 167 | + Members ({limits.used}/{limits.limit}) |
| 168 | + </Header2> |
| 169 | + <ul className="divide-ui-border flex w-full max-w-md flex-col divide-y border-b border-grid-bright"> |
| 170 | + {members.map((member) => ( |
| 171 | + <li key={member.user.id} className="flex items-center gap-x-4 py-4"> |
| 172 | + <UserAvatar |
| 173 | + avatarUrl={member.user.avatarUrl} |
| 174 | + name={member.user.name} |
| 175 | + className="h-10 w-10" |
| 176 | + /> |
| 177 | + <div className="flex flex-col gap-0.5"> |
| 178 | + <Header3> |
| 179 | + {member.user.name}{" "} |
| 180 | + {member.user.id === user.id && <span className="text-text-dimmed">(You)</span>} |
| 181 | + </Header3> |
| 182 | + <Paragraph variant="small">{member.user.email}</Paragraph> |
| 183 | + </div> |
| 184 | + <div className="flex grow items-center justify-end gap-4"> |
| 185 | + <LeaveRemoveButton |
| 186 | + userId={user.id} |
| 187 | + member={member} |
| 188 | + memberCount={members.length} |
| 189 | + /> |
| 190 | + </div> |
| 191 | + </li> |
| 192 | + ))} |
| 193 | + </ul> |
| 194 | + |
| 195 | + {invites.length > 0 && ( |
| 196 | + <> |
| 197 | + <Header2 className="mt-4">Pending invites</Header2> |
| 198 | + <ul className="flex w-full max-w-md flex-col divide-y divide-charcoal-800 border-b border-charcoal-800"> |
| 199 | + {invites.map((invite) => ( |
| 200 | + <li key={invite.id} className="flex items-center gap-4 py-4"> |
| 201 | + <div className="rounded-md border border-charcoal-750 bg-charcoal-800 p-1.5"> |
| 202 | + <EnvelopeIcon className="size-7 text-cyan-500" /> |
| 203 | + </div> |
| 204 | + <div className="flex flex-col gap-0.5"> |
| 205 | + <Header3>{invite.email}</Header3> |
| 206 | + <Paragraph variant="small"> |
| 207 | + Invite sent {<DateTime date={invite.updatedAt} />} |
| 208 | + </Paragraph> |
| 209 | + </div> |
| 210 | + <div className="flex grow items-center justify-end gap-x-2"> |
| 211 | + <ResendButton invite={invite} /> |
| 212 | + <RevokeButton invite={invite} /> |
| 213 | + </div> |
| 214 | + </li> |
| 215 | + ))} |
| 216 | + </ul> |
| 217 | + </> |
| 218 | + )} |
| 219 | + |
| 220 | + {requiresUpgrade ? ( |
| 221 | + <InfoPanel |
| 222 | + variant="upgrade" |
| 223 | + icon={LockOpenIcon} |
| 224 | + iconClassName="text-indigo-500" |
| 225 | + title="Unlock more team members" |
| 226 | + to={v3BillingPath(organization)} |
| 227 | + buttonLabel="Upgrade" |
| 228 | + panelClassName="mt-4 max-w-sm" |
232 | 229 | >
|
233 |
| - Invite a team member |
234 |
| - </LinkButton> |
235 |
| - </div> |
236 |
| - )} |
| 230 | + <Paragraph variant="small"> |
| 231 | + You've used all {limits.limit} of your available team members. Upgrade your plan to |
| 232 | + enable more. |
| 233 | + </Paragraph> |
| 234 | + </InfoPanel> |
| 235 | + ) : ( |
| 236 | + <div className="mt-4 flex max-w-md justify-end"> |
| 237 | + <LinkButton |
| 238 | + to={inviteTeamMemberPath(organization)} |
| 239 | + variant={"primary/small"} |
| 240 | + LeadingIcon={UserPlusIcon} |
| 241 | + > |
| 242 | + Invite a team member |
| 243 | + </LinkButton> |
| 244 | + </div> |
| 245 | + )} |
| 246 | + </MainHorizontallyCenteredContainer> |
237 | 247 | </PageBody>
|
238 | 248 | </PageContainer>
|
239 | 249 | );
|
|
0 commit comments