feat: implement membership confirmation flow and update related functionalities
This commit is contained in:
@@ -47,16 +47,13 @@ class AccountsApi {
|
||||
}
|
||||
|
||||
/**
|
||||
* @name loadUserAccounts
|
||||
* Load only user-owned accounts (not just memberships).
|
||||
*/
|
||||
* @name loadUserAccounts
|
||||
* Load only user-owned accounts (not just memberships).
|
||||
*/
|
||||
async loadUserAccounts() {
|
||||
const authUser = await this.client.auth.getUser();
|
||||
|
||||
const {
|
||||
data,
|
||||
error: userError,
|
||||
} = authUser
|
||||
const { data, error: userError } = authUser;
|
||||
|
||||
if (userError) {
|
||||
throw userError;
|
||||
@@ -66,14 +63,16 @@ class AccountsApi {
|
||||
|
||||
const { data: accounts, error } = await this.client
|
||||
.from('accounts_memberships')
|
||||
.select(`
|
||||
.select(
|
||||
`
|
||||
account_id,
|
||||
user_accounts (
|
||||
name,
|
||||
slug,
|
||||
picture_url
|
||||
picture_url,
|
||||
)
|
||||
`,
|
||||
)
|
||||
`)
|
||||
.eq('user_id', user.id)
|
||||
.eq('account_role', 'owner');
|
||||
|
||||
@@ -88,7 +87,6 @@ class AccountsApi {
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
async loadTempUserAccounts() {
|
||||
const { data: accounts, error } = await this.client
|
||||
.from('user_accounts')
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
"./mfa": "./src/mfa.ts",
|
||||
"./captcha/client": "./src/captcha/client/index.ts",
|
||||
"./captcha/server": "./src/captcha/server/index.ts",
|
||||
"./resend-email-link": "./src/components/resend-auth-link-form.tsx"
|
||||
"./resend-email-link": "./src/components/resend-auth-link-form.tsx",
|
||||
"./lib/utils/*": "./src/lib/utils/*.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hookform/resolvers": "^5.0.1",
|
||||
|
||||
@@ -55,14 +55,14 @@ export function SignInMethodsContainer(props: {
|
||||
}
|
||||
|
||||
try {
|
||||
const { data: hasPersonalCode } = await client.rpc(
|
||||
'has_personal_code',
|
||||
const { data: hasConsentPersonalData } = await client.rpc(
|
||||
'has_consent_personal_data',
|
||||
{
|
||||
account_id: userId,
|
||||
},
|
||||
);
|
||||
|
||||
if (hasPersonalCode) {
|
||||
if (hasConsentPersonalData) {
|
||||
router.replace(props.paths.returnPath);
|
||||
} else {
|
||||
router.replace(props.paths.updateAccount);
|
||||
|
||||
@@ -23,7 +23,7 @@ export interface AccountSubmitData {
|
||||
}
|
||||
|
||||
export const onUpdateAccount = enhanceAction(
|
||||
async (params) => {
|
||||
async (params: AccountSubmitData) => {
|
||||
const client = getSupabaseServerClient();
|
||||
const api = createAuthApi(client);
|
||||
|
||||
@@ -36,7 +36,14 @@ export const onUpdateAccount = enhanceAction(
|
||||
}
|
||||
console.warn('On update account error: ', err);
|
||||
}
|
||||
redirect(pathsConfig.auth.updateAccountSuccess);
|
||||
const hasUnseenMembershipConfirmation =
|
||||
await api.hasUnseenMembershipConfirmation();
|
||||
|
||||
if (hasUnseenMembershipConfirmation) {
|
||||
redirect(pathsConfig.auth.membershipConfirmation);
|
||||
} else {
|
||||
redirect(pathsConfig.app.selectPackage);
|
||||
}
|
||||
},
|
||||
{
|
||||
schema: UpdateAccountSchema,
|
||||
|
||||
@@ -13,14 +13,24 @@ class AuthApi {
|
||||
constructor(private readonly client: SupabaseClient<Database>) {}
|
||||
|
||||
/**
|
||||
* @name hasPersonalCode
|
||||
* @description Check if given account ID has added personal code.
|
||||
* @param id
|
||||
* @name hasUnseenMembershipConfirmation
|
||||
* @description Check if given user ID has any unseen membership confirmation.
|
||||
*/
|
||||
async hasPersonalCode(id: string) {
|
||||
const { data, error } = await this.client.rpc('has_personal_code', {
|
||||
account_id: id,
|
||||
});
|
||||
async hasUnseenMembershipConfirmation() {
|
||||
const {
|
||||
data: { user },
|
||||
} = await this.client.auth.getUser();
|
||||
|
||||
if (!user) {
|
||||
throw new Error('User not authenticated');
|
||||
}
|
||||
|
||||
const { data, error } = await this.client.rpc(
|
||||
'has_unseen_membership_confirmation',
|
||||
{
|
||||
p_user_id: user.id,
|
||||
},
|
||||
);
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export * from './notifications-popover';
|
||||
export * from './success-notification';
|
||||
export * from './update-account-success-notification';
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
import pathsConfig from '@/config/paths.config';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { usePersonalAccountData } from '@kit/accounts/hooks/use-personal-account-data';
|
||||
|
||||
import { SuccessNotification } from './success-notification';
|
||||
|
||||
export const UpdateAccountSuccessNotification = ({
|
||||
userId,
|
||||
}: {
|
||||
userId?: string;
|
||||
}) => {
|
||||
const { t } = useTranslation('account');
|
||||
|
||||
if (!userId) {
|
||||
redirect(pathsConfig.app.home);
|
||||
}
|
||||
|
||||
const { data: accountData } = usePersonalAccountData(userId);
|
||||
|
||||
return (
|
||||
<SuccessNotification
|
||||
showLogo={false}
|
||||
title={t('account:updateAccount:successTitle', {
|
||||
firstName: accountData?.name,
|
||||
lastName: accountData?.last_name,
|
||||
})}
|
||||
descriptionKey="account:updateAccount:successDescription"
|
||||
buttonProps={{
|
||||
buttonTitleKey: 'account:updateAccount:successButton',
|
||||
href: pathsConfig.app.selectPackage,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -117,7 +117,10 @@ class AccountInvitationsService {
|
||||
}
|
||||
|
||||
const isUserAlreadyMember = members.find((member) => {
|
||||
return member.email === invitation.email || member.personal_code === invitation.personal_code;
|
||||
return (
|
||||
member.email === invitation.email ||
|
||||
member.personal_code === invitation.personal_code
|
||||
);
|
||||
});
|
||||
|
||||
if (isUserAlreadyMember) {
|
||||
|
||||
@@ -17,7 +17,7 @@ export type Database = {
|
||||
changed_data: Json | null
|
||||
id: number
|
||||
operation: string
|
||||
record_key: number | null
|
||||
record_key: string | null
|
||||
row_data: Json | null
|
||||
schema_name: string
|
||||
table_name: string
|
||||
@@ -29,7 +29,7 @@ export type Database = {
|
||||
changed_data?: Json | null
|
||||
id?: number
|
||||
operation: string
|
||||
record_key?: number | null
|
||||
record_key?: string | null
|
||||
row_data?: Json | null
|
||||
schema_name: string
|
||||
table_name: string
|
||||
@@ -41,7 +41,7 @@ export type Database = {
|
||||
changed_data?: Json | null
|
||||
id?: number
|
||||
operation?: string
|
||||
record_key?: number | null
|
||||
record_key?: string | null
|
||||
row_data?: Json | null
|
||||
schema_name?: string
|
||||
table_name?: string
|
||||
@@ -252,6 +252,7 @@ export type Database = {
|
||||
account_role: string
|
||||
created_at: string
|
||||
created_by: string | null
|
||||
has_seen_confirmation: boolean
|
||||
updated_at: string
|
||||
updated_by: string | null
|
||||
user_id: string
|
||||
@@ -261,6 +262,7 @@ export type Database = {
|
||||
account_role: string
|
||||
created_at?: string
|
||||
created_by?: string | null
|
||||
has_seen_confirmation?: boolean
|
||||
updated_at?: string
|
||||
updated_by?: string | null
|
||||
user_id: string
|
||||
@@ -270,6 +272,7 @@ export type Database = {
|
||||
account_role?: string
|
||||
created_at?: string
|
||||
created_by?: string | null
|
||||
has_seen_confirmation?: boolean
|
||||
updated_at?: string
|
||||
updated_by?: string | null
|
||||
user_id?: string
|
||||
@@ -901,74 +904,21 @@ export type Database = {
|
||||
},
|
||||
]
|
||||
}
|
||||
medreport_product_groups: {
|
||||
Row: {
|
||||
created_at: string
|
||||
id: number
|
||||
name: string
|
||||
updated_at: string | null
|
||||
}
|
||||
Insert: {
|
||||
created_at?: string
|
||||
id?: number
|
||||
name: string
|
||||
updated_at?: string | null
|
||||
}
|
||||
Update: {
|
||||
created_at?: string
|
||||
id?: number
|
||||
name?: string
|
||||
updated_at?: string | null
|
||||
}
|
||||
Relationships: []
|
||||
}
|
||||
medreport_products: {
|
||||
Row: {
|
||||
created_at: string
|
||||
id: number
|
||||
name: string
|
||||
product_group_id: number | null
|
||||
updated_at: string | null
|
||||
}
|
||||
Insert: {
|
||||
created_at?: string
|
||||
id?: number
|
||||
name: string
|
||||
product_group_id?: number | null
|
||||
updated_at?: string | null
|
||||
}
|
||||
Update: {
|
||||
created_at?: string
|
||||
id?: number
|
||||
name?: string
|
||||
product_group_id?: number | null
|
||||
updated_at?: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "medreport_products_product_groups_id_fkey"
|
||||
columns: ["product_group_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "medreport_product_groups"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
medreport_products_analyses_relations: {
|
||||
medusa_products_analyses_relations: {
|
||||
Row: {
|
||||
analysis_element_id: number | null
|
||||
analysis_id: number | null
|
||||
product_id: number
|
||||
medusa_product_id: number
|
||||
}
|
||||
Insert: {
|
||||
analysis_element_id?: number | null
|
||||
analysis_id?: number | null
|
||||
product_id: number
|
||||
medusa_product_id: number
|
||||
}
|
||||
Update: {
|
||||
analysis_element_id?: number | null
|
||||
analysis_id?: number | null
|
||||
product_id?: number
|
||||
medusa_product_id?: number
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
@@ -985,27 +935,20 @@ export type Database = {
|
||||
referencedRelation: "analyses"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "medreport_products_analyses_product_id_fkey"
|
||||
columns: ["product_id"]
|
||||
isOneToOne: true
|
||||
referencedRelation: "medreport_products"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
medreport_products_external_services_relations: {
|
||||
medusa_products_external_services_relations: {
|
||||
Row: {
|
||||
connected_online_service_id: number
|
||||
product_id: number
|
||||
medusa_product_id: number
|
||||
}
|
||||
Insert: {
|
||||
connected_online_service_id: number
|
||||
product_id: number
|
||||
medusa_product_id: number
|
||||
}
|
||||
Update: {
|
||||
connected_online_service_id?: number
|
||||
product_id?: number
|
||||
medusa_product_id?: number
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
@@ -1015,13 +958,6 @@ export type Database = {
|
||||
referencedRelation: "connected_online_services"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "medreport_products_connected_online_services_product_id_fkey"
|
||||
columns: ["product_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "medreport_products"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
nonces: {
|
||||
@@ -1464,10 +1400,6 @@ export type Database = {
|
||||
Args: { target_team_account_id: string; target_user_id: string }
|
||||
Returns: boolean
|
||||
}
|
||||
check_personal_code_exists: {
|
||||
Args: { code: string }
|
||||
Returns: boolean
|
||||
}
|
||||
create_invitation: {
|
||||
Args: { account_id: string; email: string; role: string }
|
||||
Returns: {
|
||||
@@ -1574,6 +1506,10 @@ export type Database = {
|
||||
Args: { target_account_id: string }
|
||||
Returns: boolean
|
||||
}
|
||||
has_consent_personal_data: {
|
||||
Args: { account_id: string }
|
||||
Returns: boolean
|
||||
}
|
||||
has_more_elevated_role: {
|
||||
Args: {
|
||||
target_user_id: string
|
||||
@@ -1590,10 +1526,6 @@ export type Database = {
|
||||
}
|
||||
Returns: boolean
|
||||
}
|
||||
has_personal_code: {
|
||||
Args: { account_id: string }
|
||||
Returns: boolean
|
||||
}
|
||||
has_role_on_account: {
|
||||
Args: { account_id: string; account_role?: string }
|
||||
Returns: boolean
|
||||
@@ -1606,6 +1538,10 @@ export type Database = {
|
||||
}
|
||||
Returns: boolean
|
||||
}
|
||||
has_unseen_membership_confirmation: {
|
||||
Args: { p_user_id?: string }
|
||||
Returns: boolean
|
||||
}
|
||||
is_aal2: {
|
||||
Args: Record<PropertyKey, never>
|
||||
Returns: boolean
|
||||
|
||||
Reference in New Issue
Block a user