Implement invitation renewal and optimize revalidation function
This commit adds a new function to renew team invitations and a central function for revalidating member page. It also removes redundant revalidations across different actions. The renew invitation function and UI elements are introduced including a new dialog for confirming the renewal action. Furthermore, function revalidateMemberPage() is added to abstract the revalidation path used multiple times in different functions. The code readability and maintainability have thus been improved.
This commit is contained in:
@@ -2,11 +2,10 @@
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import type { Session } from '@supabase/supabase-js';
|
||||
|
||||
import { ArrowLeftCircle, ArrowRightCircle } from 'lucide-react';
|
||||
|
||||
import { AccountSelector } from '@kit/accounts/account-selector';
|
||||
import { If } from '@kit/ui/if';
|
||||
import { Sidebar, SidebarContent } from '@kit/ui/sidebar';
|
||||
import {
|
||||
Tooltip,
|
||||
@@ -58,6 +57,7 @@ function SidebarContainer(props: {
|
||||
accounts: AccountModel[];
|
||||
collapsed: boolean;
|
||||
setCollapsed: (collapsed: boolean) => void;
|
||||
collapsible?: boolean;
|
||||
}) {
|
||||
const { account, accounts } = props;
|
||||
const router = useRouter();
|
||||
@@ -88,10 +88,12 @@ function SidebarContainer(props: {
|
||||
<SidebarContent>
|
||||
<ProfileAccountDropdownContainer collapsed={props.collapsed} />
|
||||
|
||||
<AppSidebarFooterMenu
|
||||
collapsed={props.collapsed}
|
||||
setCollapsed={props.setCollapsed}
|
||||
/>
|
||||
<If condition={props.collapsible}>
|
||||
<AppSidebarFooterMenu
|
||||
collapsed={props.collapsed}
|
||||
setCollapsed={props.setCollapsed}
|
||||
/>
|
||||
</If>
|
||||
</SidebarContent>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -10,15 +10,18 @@ import pathsConfig from '~/config/paths.config';
|
||||
interface Params {
|
||||
searchParams: {
|
||||
error: string;
|
||||
invite_token: string;
|
||||
};
|
||||
}
|
||||
|
||||
function AuthCallbackErrorPage({ searchParams }: Params) {
|
||||
const { error } = searchParams;
|
||||
const { error, invite_token } = searchParams;
|
||||
const queryParam = invite_token ? `?invite_token=${invite_token}` : '';
|
||||
const signInPath = pathsConfig.auth.signIn + queryParam;
|
||||
|
||||
// if there is no error, redirect the user to the sign-in page
|
||||
if (!error) {
|
||||
redirect(pathsConfig.auth.signIn);
|
||||
redirect(signInPath);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -36,7 +39,7 @@ function AuthCallbackErrorPage({ searchParams }: Params) {
|
||||
</div>
|
||||
|
||||
<Button>
|
||||
<Link href={pathsConfig.auth.signIn}>
|
||||
<Link href={signInPath}>
|
||||
<Trans i18nKey={'auth:signIn'} />
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import Link from 'next/link';
|
||||
import { notFound, redirect } from 'next/navigation';
|
||||
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
|
||||
import { Logger } from '@kit/shared/logger';
|
||||
import { requireAuth } from '@kit/supabase/require-auth';
|
||||
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
||||
import { AcceptInvitationContainer } from '@kit/team-accounts/components';
|
||||
import { Button } from '@kit/ui/button';
|
||||
import { Heading } from '@kit/ui/heading';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import pathsConfig from '~/config/paths.config';
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
@@ -42,7 +48,7 @@ async function JoinTeamAccountPage({ searchParams }: Context) {
|
||||
const invitation = await getInviteDataFromInviteToken(token);
|
||||
|
||||
if (!invitation) {
|
||||
notFound();
|
||||
return <InviteNotFoundOrExpired />;
|
||||
}
|
||||
|
||||
// we need to verify the user isn't already in the account
|
||||
@@ -124,13 +130,39 @@ async function getInviteDataFromInviteToken(token: string) {
|
||||
picture_url: string;
|
||||
};
|
||||
}
|
||||
>('id, account: account_id !inner (id, name, slug, picture_url)')
|
||||
>(
|
||||
'id, expires_at, account: account_id !inner (id, name, slug, picture_url)',
|
||||
)
|
||||
.eq('invite_token', token)
|
||||
.rangeLt('expires_at', new Date().toISOString())
|
||||
.single();
|
||||
|
||||
console.log(invitation, error);
|
||||
|
||||
if (!invitation ?? error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return invitation;
|
||||
}
|
||||
|
||||
function InviteNotFoundOrExpired() {
|
||||
return (
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<Heading level={6}>
|
||||
<Trans i18nKey={'teams:inviteNotFoundOrExpired'} />
|
||||
</Heading>
|
||||
|
||||
<p className={'text-sm text-muted-foreground'}>
|
||||
<Trans i18nKey={'teams:inviteNotFoundOrExpiredDescription'} />
|
||||
</p>
|
||||
|
||||
<Link href={pathsConfig.app.home}>
|
||||
<Button className={'w-full'} variant={'outline'}>
|
||||
<ArrowLeft className={'mr-2 w-4'} />
|
||||
<Trans i18nKey={'teams:backToHome'} />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -135,6 +135,18 @@
|
||||
"updateInvitation": "Update Invitation",
|
||||
"removeInvitation": "Remove Invitation",
|
||||
"acceptInvitation": "Accept Invitation",
|
||||
"renewInvitation": "Renew Invitation",
|
||||
"resendInvitation": "Resend Invitation",
|
||||
"expiresAtLabel": "Expires at",
|
||||
"expired": "Expired",
|
||||
"active": "Active",
|
||||
"inviteStatus": "Status",
|
||||
"inviteNotFoundOrExpired": "Invite not found or expired",
|
||||
"inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the team owner to renew the invite.",
|
||||
"backToHome": "Back to Home",
|
||||
"renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the team.",
|
||||
"renewInvitationErrorTitle": "Sorry, we couldn't renew the invitation.",
|
||||
"renewInvitationErrorDescription": "We encountered an error renewing the invitation. Please try again.",
|
||||
"signInWithDifferentAccount": "Sign in with a different account",
|
||||
"signInWithDifferentAccountDescription": "If you wish to accept the invitation with a different account, please sign out and back in with the account you wish to use.",
|
||||
"acceptInvitationHeading": "Accept Invitation to join {{accountName}}",
|
||||
|
||||
Reference in New Issue
Block a user