diff --git a/README.md b/README.md index 21d54ba..2a986d8 100644 --- a/README.md +++ b/README.md @@ -78,3 +78,12 @@ npm run supabase:typegen:app To get medusa store working you need to update the env's to your running medusa app and migrate the tables from medusa project to your supabase project You can get `NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY` from your medusa app settings + +## Super admin + +To access admin pages follow these steps: + +- Register new user +- Go to Profile and add Multi-Factor Authentication +- Sign out and Sign in +- Authenticate with mfa (at current time profile page prompts it again) diff --git a/app/(public)/company-offer/page.tsx b/app/(public)/company-offer/page.tsx index bf68684..4f293e5 100644 --- a/app/(public)/company-offer/page.tsx +++ b/app/(public)/company-offer/page.tsx @@ -6,6 +6,7 @@ import { useRouter } from 'next/navigation'; import { MedReportLogo } from '@/components/med-report-logo'; import { SubmitButton } from '@/components/ui/submit-button'; +import { withI18n } from '@/lib/i18n/with-i18n'; import { sendCompanyOfferEmail } from '@/lib/services/mailer.service'; import { CompanySubmitData } from '@/lib/types/company'; import { companyOfferSchema } from '@/lib/validations/company-offer.schema'; @@ -18,7 +19,7 @@ import { Input } from '@kit/ui/input'; import { Label } from '@kit/ui/label'; import { Trans } from '@kit/ui/trans'; -export default function CompanyOffer() { +function CompanyOffer() { const router = useRouter(); const { register, @@ -100,3 +101,5 @@ export default function CompanyOffer() { ); } + +export default withI18n(CompanyOffer); diff --git a/app/admin/accounts/[id]/page.tsx b/app/admin/accounts/[id]/page.tsx index 02c9ee4..0417247 100644 --- a/app/admin/accounts/[id]/page.tsx +++ b/app/admin/accounts/[id]/page.tsx @@ -34,6 +34,7 @@ async function accountLoader(id: string) { const client = getSupabaseServerClient(); const { data, error } = await client + .schema('medreport') .from('accounts') .select('*, memberships: accounts_memberships (*)') .eq('id', id) diff --git a/packages/features/notifications/src/components/update-account-success-notification.tsx b/app/auth/membership-confirmation/_components/membership-confirmation-notification.tsx similarity index 51% rename from packages/features/notifications/src/components/update-account-success-notification.tsx rename to app/auth/membership-confirmation/_components/membership-confirmation-notification.tsx index b36c79b..ad1e446 100644 --- a/packages/features/notifications/src/components/update-account-success-notification.tsx +++ b/app/auth/membership-confirmation/_components/membership-confirmation-notification.tsx @@ -1,39 +1,34 @@ 'use client'; -import { redirect } from 'next/navigation'; +import React from 'react'; import pathsConfig from '@/config/paths.config'; import { useTranslation } from 'react-i18next'; import { usePersonalAccountData } from '@kit/accounts/hooks/use-personal-account-data'; +import { SuccessNotification } from '@kit/notifications/components'; -import { SuccessNotification } from './success-notification'; - -export const UpdateAccountSuccessNotification = ({ - userId, -}: { - userId?: string; -}) => { - const { t } = useTranslation('account'); - - if (!userId) { - redirect(pathsConfig.app.home); - } +const MembershipConfirmationNotification: React.FC<{ + userId: string; +}> = ({ userId }) => { + const { t } = useTranslation(); const { data: accountData } = usePersonalAccountData(userId); return ( ); }; + +export default MembershipConfirmationNotification; diff --git a/app/auth/membership-confirmation/layout.tsx b/app/auth/membership-confirmation/layout.tsx new file mode 100644 index 0000000..e3d32c7 --- /dev/null +++ b/app/auth/membership-confirmation/layout.tsx @@ -0,0 +1,11 @@ +import { withI18n } from '~/lib/i18n/with-i18n'; + +async function SiteLayout(props: React.PropsWithChildren) { + return ( +
+ {props.children} +
+ ); +} + +export default SiteLayout; diff --git a/app/auth/membership-confirmation/page.tsx b/app/auth/membership-confirmation/page.tsx new file mode 100644 index 0000000..43c0f2c --- /dev/null +++ b/app/auth/membership-confirmation/page.tsx @@ -0,0 +1,25 @@ +import { redirect } from 'next/navigation'; + +import pathsConfig from '@/config/paths.config'; + +import { getSupabaseServerClient } from '@kit/supabase/server-client'; + +import { withI18n } from '~/lib/i18n/with-i18n'; + +import MembershipConfirmationNotification from './_components/membership-confirmation-notification'; + +async function UpdateAccountSuccess() { + const client = getSupabaseServerClient(); + + const { + data: { user }, + } = await client.auth.getUser(); + + if (!user?.id) { + redirect(pathsConfig.app.home); + } + + return ; +} + +export default withI18n(UpdateAccountSuccess); diff --git a/app/auth/update-account/success/page.tsx b/app/auth/update-account/success/page.tsx deleted file mode 100644 index a31b5d2..0000000 --- a/app/auth/update-account/success/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { getSupabaseServerClient } from '@/packages/supabase/src/clients/server-client'; - -import { UpdateAccountSuccessNotification } from '@kit/notifications/components'; - -import { withI18n } from '~/lib/i18n/with-i18n'; - -async function UpdateAccountSuccess() { - const client = getSupabaseServerClient(); - - const { - data: { user }, - } = await client.auth.getUser(); - - return ; -} - -export default withI18n(UpdateAccountSuccess); diff --git a/app/healthcheck/route.ts b/app/healthcheck/route.ts index ebb71b9..39d6fdf 100644 --- a/app/healthcheck/route.ts +++ b/app/healthcheck/route.ts @@ -26,7 +26,7 @@ async function getSupabaseHealthCheck() { try { const client = getSupabaseServerAdminClient(); - const { error } = await client.rpc('is_set', { + const { error } = await client.schema('medreport').rpc('is_set', { field_name: 'billing_provider', }); diff --git a/app/home/(user)/(dashboard)/page.tsx b/app/home/(user)/(dashboard)/page.tsx index 71aba23..2aabc91 100644 --- a/app/home/(user)/(dashboard)/page.tsx +++ b/app/home/(user)/(dashboard)/page.tsx @@ -1,3 +1,6 @@ +import { use } from 'react'; + +import { PageBody } from '@kit/ui/page'; import { Trans } from '@kit/ui/trans'; import { createI18nServerInstance } from '~/lib/i18n/i18n.server'; @@ -6,9 +9,7 @@ import { withI18n } from '~/lib/i18n/with-i18n'; import Dashboard from '../_components/dashboard'; // local imports import { HomeLayoutPageHeader } from '../_components/home-page-header'; -import { use } from 'react'; import { loadUserWorkspace } from '../_lib/server/load-user-workspace'; -import { PageBody } from '@kit/ui/page'; export const generateMetadata = async () => { const i18n = await createI18nServerInstance(); diff --git a/app/home/(user)/_lib/server/load-user-workspace.ts b/app/home/(user)/_lib/server/load-user-workspace.ts index 2a9db62..30ae4ed 100644 --- a/app/home/(user)/_lib/server/load-user-workspace.ts +++ b/app/home/(user)/_lib/server/load-user-workspace.ts @@ -35,13 +35,13 @@ async function workspaceLoader() { accountsPromise(), workspacePromise, requireUserInServerComponent(), - tempAccountsPromise() + tempAccountsPromise(), ]); return { accounts, workspace, user, - tempVisibleAccounts + tempVisibleAccounts, }; } diff --git a/app/home/[account]/members/_lib/server/members-page.loader.ts b/app/home/[account]/members/_lib/server/members-page.loader.ts index e77fd3f..6025aba 100644 --- a/app/home/[account]/members/_lib/server/members-page.loader.ts +++ b/app/home/[account]/members/_lib/server/members-page.loader.ts @@ -46,9 +46,11 @@ async function loadAccountMembers( client: SupabaseClient, account: string, ) { - const { data, error } = await client.rpc('get_account_members', { - account_slug: account, - }); + const { data, error } = await client + .schema('medreport') + .rpc('get_account_members', { + account_slug: account, + }); if (error) { console.error(error); @@ -67,9 +69,11 @@ async function loadInvitations( client: SupabaseClient, account: string, ) { - const { data, error } = await client.rpc('get_account_invitations', { - account_slug: account, - }); + const { data, error } = await client + .schema('medreport') + .rpc('get_account_invitations', { + account_slug: account, + }); if (error) { console.error(error); diff --git a/app/join/page.tsx b/app/join/page.tsx index ffe4674..1c1b061 100644 --- a/app/join/page.tsx +++ b/app/join/page.tsx @@ -79,12 +79,11 @@ async function JoinTeamAccountPage(props: JoinTeamAccountPageProps) { // we need to verify the user isn't already in the account // we do so by checking if the user can read the account // if the user can read the account, then they are already in the account - const { data: isAlreadyTeamMember } = await client.rpc( - 'is_account_team_member', - { + const { data: isAlreadyTeamMember } = await client + .schema('medreport') + .rpc('is_account_team_member', { target_account_id: invitation.account.id, - }, - ); + }); // if the user is already in the account redirect to the home page if (isAlreadyTeamMember) { diff --git a/config/paths.config.ts b/config/paths.config.ts index fdb6c6d..ebfcbea 100644 --- a/config/paths.config.ts +++ b/config/paths.config.ts @@ -10,6 +10,7 @@ const PathsSchema = z.object({ passwordUpdate: z.string().min(1), updateAccount: z.string().min(1), updateAccountSuccess: z.string().min(1), + membershipConfirmation: z.string().min(1), }), app: z.object({ home: z.string().min(1), @@ -42,6 +43,7 @@ const pathsConfig = PathsSchema.parse({ passwordUpdate: '/update-password', updateAccount: '/auth/update-account', updateAccountSuccess: '/auth/update-account/success', + membershipConfirmation: '/auth/membership-confirmation', }, app: { home: '/home', diff --git a/jobs/sync-analysis-groups.ts b/jobs/sync-analysis-groups.ts index ab34056..e375248 100644 --- a/jobs/sync-analysis-groups.ts +++ b/jobs/sync-analysis-groups.ts @@ -137,6 +137,7 @@ async function syncData() { for (const analysisGroup of analysisGroups) { // SAVE ANALYSIS GROUP const { data: insertedAnalysisGroup, error } = await supabase + .schema('medreport') .from('analysis_groups') .upsert( { @@ -174,6 +175,7 @@ async function syncData() { const analysisElement = item.UuringuElement; const { data: insertedAnalysisElement, error } = await supabase + .schema('medreport') .from('analysis_elements') .upsert( { @@ -217,6 +219,7 @@ async function syncData() { if (analyses?.length) { for (const analysis of analyses) { const { data: insertedAnalysis, error } = await supabase + .schema('medreport') .from('analyses') .upsert( { @@ -259,7 +262,7 @@ async function syncData() { } } - await supabase.from('codes').upsert(codes); + await supabase.schema('medreport').from('codes').upsert(codes); await supabase.schema('audit').from('sync_entries').insert({ operation: 'ANALYSES_SYNC', diff --git a/jobs/sync-connected-online.ts b/jobs/sync-connected-online.ts index 12e93fc..d2ad5c9 100644 --- a/jobs/sync-connected-online.ts +++ b/jobs/sync-connected-online.ts @@ -105,10 +105,12 @@ async function syncData() { }); const { error: providersError } = await supabase + .schema('medreport') .from('connected_online_providers') .upsert(mappedClinics); const { error: servicesError } = await supabase + .schema('medreport') .from('connected_online_services') .upsert(mappedServices, { onConflict: 'id', ignoreDuplicates: false }); diff --git a/lib/services/connected-online.service.ts b/lib/services/connected-online.service.ts index 8a42a21..b0ad1f6 100644 --- a/lib/services/connected-online.service.ts +++ b/lib/services/connected-online.service.ts @@ -1,5 +1,5 @@ - 'use server' - +'use server'; + import logRequestResult from '@/lib/services/audit.service'; import { RequestStatus } from '@/lib/types/audit'; import { @@ -9,7 +9,7 @@ import { ConnectedOnlineMethodName, } from '@/lib/types/connected-online'; import { ExternalApi } from '@/lib/types/external'; -import { Tables } from '@/supabase/database.types'; +import { Tables } from '@/packages/supabase/src/database.types'; import { createClient } from '@/utils/supabase/server'; import axios from 'axios'; @@ -106,11 +106,13 @@ export async function bookAppointment( { data: dbService, error: serviceError }, ] = await Promise.all([ supabase + .schema('medreport') .from('connected_online_providers') .select('*') .eq('id', clinicId) .limit(1), supabase + .schema('medreport') .from('connected_online_services') .select('*') .eq('sync_id', serviceSyncId) @@ -132,8 +134,14 @@ export async function bookAppointment( ); } - const clinic: Tables<'connected_online_providers'> = dbClinic![0]; - const service: Tables<'connected_online_services'> = dbService![0]; + const clinic: Tables< + { schema: 'medreport' }, + 'connected_online_providers' + > = dbClinic![0]; + const service: Tables< + { schema: 'medreport' }, + 'connected_online_services' + > = dbService![0]; // TODO the dummy data needs to be replaced with real values once they're present on the user/account const response = await axios.post( @@ -183,6 +191,7 @@ export async function bookAppointment( const responseParts = responseData.Value.split(','); const { error } = await supabase + .schema('medreport') .from('connected_online_reservation') .insert({ booking_code: responseParts[1], diff --git a/lib/services/medipost.service.ts b/lib/services/medipost.service.ts index e4cf7ee..7952634 100644 --- a/lib/services/medipost.service.ts +++ b/lib/services/medipost.service.ts @@ -32,6 +32,7 @@ import { toArray } from '@/lib/utils'; import axios from 'axios'; import { XMLParser } from 'fast-xml-parser'; import { uniqBy } from 'lodash'; + import { Tables } from '@kit/supabase/database'; const BASE_URL = process.env.MEDIPOST_URL!; @@ -196,6 +197,7 @@ async function saveAnalysisGroup( supabase: SupabaseClient, ) { const { data: insertedAnalysisGroup, error } = await supabase + .schema('medreport') .from('analysis_groups') .upsert( { @@ -215,13 +217,14 @@ async function saveAnalysisGroup( const analysisGroupId = insertedAnalysisGroup[0].id; const analysisGroupCodes = toArray(analysisGroup.Kood); - const codes: Partial>[] = analysisGroupCodes.map((kood) => ({ - hk_code: kood.HkKood, - hk_code_multiplier: kood.HkKoodiKordaja, - coefficient: kood.Koefitsient, - price: kood.Hind, - analysis_group_id: analysisGroupId, - })); + const codes: Partial>[] = + analysisGroupCodes.map((kood) => ({ + hk_code: kood.HkKood, + hk_code_multiplier: kood.HkKoodiKordaja, + coefficient: kood.Koefitsient, + price: kood.Hind, + analysis_group_id: analysisGroupId, + })); const analysisGroupItems = toArray(analysisGroup.Uuring); @@ -229,6 +232,7 @@ async function saveAnalysisGroup( const analysisElement = item.UuringuElement; const { data: insertedAnalysisElement, error } = await supabase + .schema('medreport') .from('analysis_elements') .upsert( { @@ -270,6 +274,7 @@ async function saveAnalysisGroup( if (analyses?.length) { for (const analysis of analyses) { const { data: insertedAnalysis, error } = await supabase + .schema('medreport') .from('analyses') .upsert( { @@ -310,6 +315,7 @@ async function saveAnalysisGroup( } const { error: codesError } = await supabase + .schema('medreport') .from('codes') .upsert(codes, { ignoreDuplicates: false }); @@ -404,34 +410,41 @@ export async function composeOrderXML( }; const { data: analysisElements } = (await supabase + .schema('medreport') .from('analysis_elements') .select(`*, analysis_groups(*)`) .in('id', orderedElements)) as { data: ({ - analysis_groups: Tables<'analysis_groups'>; - } & Tables<'analysis_elements'>)[]; + analysis_groups: Tables<{ schema: 'medreport' }, 'analysis_groups'>; + } & Tables<{ schema: 'medreport' }, 'analysis_elements'>)[]; }; const { data: analyses } = (await supabase + .schema('medreport') .from('analyses') .select(`*, analysis_elements(*, analysis_groups(*))`) .in('id', orderedAnalyses)) as { data: ({ - analysis_elements: Tables<'analysis_elements'> & { - analysis_groups: Tables<'analysis_groups'>; + analysis_elements: Tables< + { schema: 'medreport' }, + 'analysis_elements' + > & { + analysis_groups: Tables<{ schema: 'medreport' }, 'analysis_groups'>; }; - } & Tables<'analyses'>)[]; + } & Tables<{ schema: 'medreport' }, 'analyses'>)[]; }; - const analysisGroups: Tables<'analysis_groups'>[] = uniqBy( - ( - analysisElements?.flatMap(({ analysis_groups }) => analysis_groups) ?? [] - ).concat( - analyses?.flatMap( - ({ analysis_elements }) => analysis_elements.analysis_groups, - ) ?? [], - ), - 'id', - ); + const analysisGroups: Tables<{ schema: 'medreport' }, 'analysis_groups'>[] = + uniqBy( + ( + analysisElements?.flatMap(({ analysis_groups }) => analysis_groups) ?? + [] + ).concat( + analyses?.flatMap( + ({ analysis_elements }) => analysis_elements.analysis_groups, + ) ?? [], + ), + 'id', + ); const specimenSection = []; const analysisSection = []; @@ -545,6 +558,7 @@ export async function syncPrivateMessage( const status = response.TellimuseOlek; const { data: analysisOrder, error: analysisOrderError } = await supabase + .schema('medreport') .from('analysis_orders') .select('user_id') .eq('id', response.ValisTellimuseId); @@ -556,6 +570,7 @@ export async function syncPrivateMessage( } const { data: analysisResponse, error } = await supabase + .schema('medreport') .from('analysis_responses') .upsert( { @@ -576,7 +591,7 @@ export async function syncPrivateMessage( const analysisGroups = toArray(response.UuringuGrupp); const responses: Omit< - Tables<'analysis_response_elements'>, + Tables<{ schema: 'medreport' }, 'analysis_response_elements'>, 'id' | 'created_at' | 'updated_at' >[] = []; for (const analysisGroup of analysisGroups) { @@ -608,6 +623,7 @@ export async function syncPrivateMessage( } const { error: deleteError } = await supabase + .schema('medreport') .from('analysis_response_elements') .delete() .eq('analysis_response_id', analysisResponse[0].id); @@ -619,6 +635,7 @@ export async function syncPrivateMessage( } const { error: elementInsertError } = await supabase + .schema('medreport') .from('analysis_response_elements') .insert(responses); diff --git a/lib/templates/medipost-order.ts b/lib/templates/medipost-order.ts index 9b045e6..9439438 100644 --- a/lib/templates/medipost-order.ts +++ b/lib/templates/medipost-order.ts @@ -1,5 +1,5 @@ import { DATE_TIME_FORMAT } from '@/lib/constants'; -import { Tables } from '@/supabase/database.types'; +import { Tables } from '@/packages/supabase/src/database.types'; import { format } from 'date-fns'; const isProd = process.env.NODE_ENV === 'production'; @@ -160,7 +160,7 @@ export const getAnalysisGroup = ( analysisGroupOriginalId: string, analysisGroupName: string, specimenOrderNr: number, - analysisElement: Tables<'analysis_elements'>, + analysisElement: Tables<{ schema: 'medreport' }, 'analysis_elements'>, ) => ` ${analysisGroupOriginalId} diff --git a/middleware.ts b/middleware.ts index c9283b7..1739283 100644 --- a/middleware.ts +++ b/middleware.ts @@ -139,7 +139,7 @@ function getPatterns() { handler: adminMiddleware, }, { - pattern: new URLPattern({ pathname: '/auth/update-account' }), + pattern: new URLPattern({ pathname: '/auth/*?' }), handler: async (req: NextRequest, res: NextResponse) => { const { data: { user }, diff --git a/package.json b/package.json index 6935f2d..ce946e8 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "pino-pretty": "^13.0.0", "prettier": "^3.5.3", "react-hook-form": "^7.57.0", - "supabase": "^2.26.9", + "supabase": "^2.30.4", "tailwindcss": "4.1.7", "tailwindcss-animate": "^1.0.7", "typescript": "^5.8.3", diff --git a/packages/billing/core/src/types/index.ts b/packages/billing/core/src/types/index.ts index 91ad002..f666e88 100644 --- a/packages/billing/core/src/types/index.ts +++ b/packages/billing/core/src/types/index.ts @@ -1,7 +1,7 @@ import { Database } from '@kit/supabase/database'; export type UpsertSubscriptionParams = - Database['public']['Functions']['upsert_subscription']['Args'] & { + Database['medreport']['Functions']['upsert_subscription']['Args'] & { line_items: Array; }; @@ -19,4 +19,4 @@ interface LineItem { } export type UpsertOrderParams = - Database['public']['Functions']['upsert_order']['Args']; + Database['medreport']['Functions']['upsert_order']['Args']; diff --git a/packages/billing/gateway/package.json b/packages/billing/gateway/package.json index 7693df5..94446f3 100644 --- a/packages/billing/gateway/package.json +++ b/packages/billing/gateway/package.json @@ -32,8 +32,7 @@ "lucide-react": "^0.510.0", "next": "15.3.2", "react": "19.1.0", - "react-hook-form": "^7.56.3", - "react-i18next": "^15.5.1" + "react-hook-form": "^7.56.3" }, "typesVersions": { "*": { diff --git a/packages/billing/gateway/src/components/current-lifetime-order-card.tsx b/packages/billing/gateway/src/components/current-lifetime-order-card.tsx index 8001226..fd24ab0 100644 --- a/packages/billing/gateway/src/components/current-lifetime-order-card.tsx +++ b/packages/billing/gateway/src/components/current-lifetime-order-card.tsx @@ -14,8 +14,8 @@ import { Trans } from '@kit/ui/trans'; import { CurrentPlanBadge } from './current-plan-badge'; import { LineItemDetails } from './line-item-details'; -type Order = Tables<'orders'>; -type LineItem = Tables<'order_items'>; +type Order = Tables<{ schema: 'medreport' }, 'orders'>; +type LineItem = Tables<{ schema: 'medreport' }, 'order_items'>; interface Props { order: Order & { diff --git a/packages/billing/gateway/src/components/current-subscription-card.tsx b/packages/billing/gateway/src/components/current-subscription-card.tsx index bf608e1..072118d 100644 --- a/packages/billing/gateway/src/components/current-subscription-card.tsx +++ b/packages/billing/gateway/src/components/current-subscription-card.tsx @@ -18,8 +18,8 @@ import { CurrentPlanAlert } from './current-plan-alert'; import { CurrentPlanBadge } from './current-plan-badge'; import { LineItemDetails } from './line-item-details'; -type Subscription = Tables<'subscriptions'>; -type LineItem = Tables<'subscription_items'>; +type Subscription = Tables<{ schema: 'medreport' }, 'subscriptions'>; +type LineItem = Tables<{ schema: 'medreport' }, 'subscription_items'>; interface Props { subscription: Subscription & { diff --git a/packages/billing/gateway/src/server/services/billing-event-handler/billing-event-handler.service.ts b/packages/billing/gateway/src/server/services/billing-event-handler/billing-event-handler.service.ts index b5df880..eb8c458 100644 --- a/packages/billing/gateway/src/server/services/billing-event-handler/billing-event-handler.service.ts +++ b/packages/billing/gateway/src/server/services/billing-event-handler/billing-event-handler.service.ts @@ -86,6 +86,7 @@ class BillingEventHandlerService { logger.info(ctx, 'Processing subscription deleted event...'); const { error } = await client + .schema('medreport') .from('subscriptions') .delete() .match({ id: subscriptionId }); @@ -109,7 +110,7 @@ class BillingEventHandlerService { logger.info(ctx, 'Successfully deleted subscription'); }, onSubscriptionUpdated: async (subscription) => { - const client = this.clientProvider(); + const client = this.clientProvider().schema('medreport'); const logger = await getLogger(); const ctx = { @@ -147,7 +148,7 @@ class BillingEventHandlerService { onCheckoutSessionCompleted: async (payload) => { // Handle the checkout session completed event // here we add the subscription to the database - const client = this.clientProvider(); + const client = this.clientProvider().schema('medreport'); const logger = await getLogger(); // Check if the payload contains an order_id @@ -212,7 +213,7 @@ class BillingEventHandlerService { } }, onPaymentSucceeded: async (sessionId: string) => { - const client = this.clientProvider(); + const client = this.clientProvider().schema('medreport'); const logger = await getLogger(); const ctx = { @@ -244,7 +245,7 @@ class BillingEventHandlerService { logger.info(ctx, 'Successfully updated payment status'); }, onPaymentFailed: async (sessionId: string) => { - const client = this.clientProvider(); + const client = this.clientProvider().schema('medreport'); const logger = await getLogger(); const ctx = { diff --git a/packages/billing/gateway/src/server/services/billing-gateway/billing-gateway-provider-factory.ts b/packages/billing/gateway/src/server/services/billing-gateway/billing-gateway-provider-factory.ts index 3f8dd47..2992681 100644 --- a/packages/billing/gateway/src/server/services/billing-gateway/billing-gateway-provider-factory.ts +++ b/packages/billing/gateway/src/server/services/billing-gateway/billing-gateway-provider-factory.ts @@ -21,6 +21,7 @@ export async function getBillingGatewayProvider( async function getBillingProvider(client: SupabaseClient) { const { data, error } = await client + .schema('medreport') .from('config') .select('billing_provider') .single(); diff --git a/packages/billing/gateway/src/server/services/billing-webhooks/billing-webhooks.service.ts b/packages/billing/gateway/src/server/services/billing-webhooks/billing-webhooks.service.ts index bf564cc..ff33f4b 100644 --- a/packages/billing/gateway/src/server/services/billing-webhooks/billing-webhooks.service.ts +++ b/packages/billing/gateway/src/server/services/billing-webhooks/billing-webhooks.service.ts @@ -4,7 +4,7 @@ import { Tables } from '@kit/supabase/database'; import { createBillingGatewayService } from '../billing-gateway/billing-gateway.service'; -type Subscription = Tables<'subscriptions'>; +type Subscription = Tables<{ schema: 'medreport' }, 'subscriptions'>; export function createBillingWebhooksService() { return new BillingWebhooksService(); diff --git a/packages/billing/lemon-squeezy/src/services/lemon-squeezy-webhook-handler.service.ts b/packages/billing/lemon-squeezy/src/services/lemon-squeezy-webhook-handler.service.ts index 83e0e2e..529a450 100644 --- a/packages/billing/lemon-squeezy/src/services/lemon-squeezy-webhook-handler.service.ts +++ b/packages/billing/lemon-squeezy/src/services/lemon-squeezy-webhook-handler.service.ts @@ -17,14 +17,14 @@ import { createLemonSqueezySubscriptionPayloadBuilderService } from './lemon-squ import { createHmac } from './verify-hmac'; type UpsertSubscriptionParams = - Database['public']['Functions']['upsert_subscription']['Args'] & { + Database['medreport']['Functions']['upsert_subscription']['Args'] & { line_items: Array; }; type UpsertOrderParams = - Database['public']['Functions']['upsert_order']['Args']; + Database['medreport']['Functions']['upsert_order']['Args']; -type BillingProvider = Enums<'billing_provider'>; +type BillingProvider = Enums<{ schema: 'medreport' }, 'billing_provider'>; interface LineItem { id: string; diff --git a/packages/billing/stripe/src/services/stripe-webhook-handler.service.ts b/packages/billing/stripe/src/services/stripe-webhook-handler.service.ts index 3227bd7..faa1a5c 100644 --- a/packages/billing/stripe/src/services/stripe-webhook-handler.service.ts +++ b/packages/billing/stripe/src/services/stripe-webhook-handler.service.ts @@ -9,7 +9,7 @@ import { createStripeClient } from './stripe-sdk'; import { createStripeSubscriptionPayloadBuilderService } from './stripe-subscription-payload-builder.service'; type UpsertSubscriptionParams = - Database['public']['Functions']['upsert_subscription']['Args'] & { + Database['medreport']['Functions']['upsert_subscription']['Args'] & { line_items: Array; }; @@ -27,9 +27,9 @@ interface LineItem { } type UpsertOrderParams = - Database['public']['Functions']['upsert_order']['Args']; + Database['medreport']['Functions']['upsert_order']['Args']; -type BillingProvider = Enums<'billing_provider'>; +type BillingProvider = Enums<{ schema: 'medreport' }, 'billing_provider'>; export class StripeWebhookHandlerService implements BillingWebhookHandlerService diff --git a/packages/database-webhooks/src/server/record-change.type.ts b/packages/database-webhooks/src/server/record-change.type.ts index fd1565f..f58b064 100644 --- a/packages/database-webhooks/src/server/record-change.type.ts +++ b/packages/database-webhooks/src/server/record-change.type.ts @@ -1,6 +1,6 @@ import { Database } from '@kit/supabase/database'; -export type Tables = Database['public']['Tables']; +export type Tables = Database['medreport']['Tables']; export type TableChangeType = 'INSERT' | 'UPDATE' | 'DELETE'; diff --git a/packages/features/accounts/package.json b/packages/features/accounts/package.json index 67eee71..148e428 100644 --- a/packages/features/accounts/package.json +++ b/packages/features/accounts/package.json @@ -44,7 +44,6 @@ "react": "19.1.0", "react-dom": "19.1.0", "react-hook-form": "^7.56.3", - "react-i18next": "^15.5.1", "sonner": "^2.0.3" }, "prettier": "@kit/prettier-config", diff --git a/packages/features/accounts/src/components/personal-account-settings/update-account-details-form.tsx b/packages/features/accounts/src/components/personal-account-settings/update-account-details-form.tsx index 921f766..8f9dbc8 100644 --- a/packages/features/accounts/src/components/personal-account-settings/update-account-details-form.tsx +++ b/packages/features/accounts/src/components/personal-account-settings/update-account-details-form.tsx @@ -19,7 +19,8 @@ import { Trans } from '@kit/ui/trans'; import { useUpdateAccountData } from '../../hooks/use-update-account'; import { AccountDetailsSchema } from '../../schema/account-details.schema'; -type UpdateUserDataParams = Database['public']['Tables']['accounts']['Update']; +type UpdateUserDataParams = + Database['medreport']['Tables']['accounts']['Update']; export function UpdateAccountDetailsForm({ displayName, diff --git a/packages/features/accounts/src/components/personal-account-settings/update-account-image-container.tsx b/packages/features/accounts/src/components/personal-account-settings/update-account-image-container.tsx index 0332779..93eac80 100644 --- a/packages/features/accounts/src/components/personal-account-settings/update-account-image-container.tsx +++ b/packages/features/accounts/src/components/personal-account-settings/update-account-image-container.tsx @@ -72,6 +72,7 @@ function UploadProfileAvatarForm(props: { uploadUserProfilePhoto(client, file, props.userId) .then((pictureUrl) => { return client + .schema('medreport') .from('accounts') .update({ picture_url: pictureUrl, @@ -90,6 +91,7 @@ function UploadProfileAvatarForm(props: { removeExistingStorageFile() .then(() => { return client + .schema('medreport') .from('accounts') .update({ picture_url: null, diff --git a/packages/features/accounts/src/components/user-workspace-context.tsx b/packages/features/accounts/src/components/user-workspace-context.tsx index aced8d4..916727c 100644 --- a/packages/features/accounts/src/components/user-workspace-context.tsx +++ b/packages/features/accounts/src/components/user-workspace-context.tsx @@ -17,7 +17,9 @@ interface UserWorkspace { id: string | null; name: string | null; picture_url: string | null; - subscription_status: Tables<'subscriptions'>['status'] | null; + subscription_status: + | Tables<{ schema: 'medreport' }, 'subscriptions'>['status'] + | null; }; user: User; diff --git a/packages/features/accounts/src/hooks/use-personal-account-data.ts b/packages/features/accounts/src/hooks/use-personal-account-data.ts index 83e16bc..b5379a8 100644 --- a/packages/features/accounts/src/hooks/use-personal-account-data.ts +++ b/packages/features/accounts/src/hooks/use-personal-account-data.ts @@ -21,6 +21,7 @@ export function usePersonalAccountData( } const response = await client + .schema('medreport') .from('accounts') .select() .eq('primary_owner_user_id', userId) diff --git a/packages/features/accounts/src/hooks/use-update-account.ts b/packages/features/accounts/src/hooks/use-update-account.ts index d55d259..386efb8 100644 --- a/packages/features/accounts/src/hooks/use-update-account.ts +++ b/packages/features/accounts/src/hooks/use-update-account.ts @@ -3,7 +3,7 @@ import { useMutation } from '@tanstack/react-query'; import { Database } from '@kit/supabase/database'; import { useSupabase } from '@kit/supabase/hooks/use-supabase'; -type UpdateData = Database['public']['Tables']['accounts']['Update']; +type UpdateData = Database['medreport']['Tables']['accounts']['Update']; export function useUpdateAccountData(accountId: string) { const client = useSupabase(); @@ -11,9 +11,13 @@ export function useUpdateAccountData(accountId: string) { const mutationKey = ['account:data', accountId]; const mutationFn = async (data: UpdateData) => { - const response = await client.from('accounts').update(data).match({ - id: accountId, - }); + const response = await client + .schema('medreport') + .from('accounts') + .update(data) + .match({ + id: accountId, + }); if (response.error) { throw response.error; diff --git a/packages/features/accounts/src/server/api.ts b/packages/features/accounts/src/server/api.ts index 35a4465..fd0c9d1 100644 --- a/packages/features/accounts/src/server/api.ts +++ b/packages/features/accounts/src/server/api.ts @@ -17,6 +17,7 @@ class AccountsApi { */ async getAccount(id: string) { const { data, error } = await this.client + .schema('medreport') .from('accounts') .select('*') .eq('id', id) @@ -35,6 +36,7 @@ class AccountsApi { */ async getAccountWorkspace() { const { data, error } = await this.client + .schema('medreport') .from('user_account_workspace') .select(`*`) .single(); @@ -47,50 +49,52 @@ 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) { + console.error('Failed to get user', userError); throw userError; } const { user } = data; const { data: accounts, error } = await this.client + .schema('medreport') .from('accounts_memberships') - .select(` - account_id, - user_accounts ( - name, - slug, - picture_url + .select( + ` + account_id, + accounts ( + name, + slug, + picture_url + ) + `, ) - `) .eq('user_id', user.id) .eq('account_role', 'owner'); if (error) { + console.error('error', error); throw error; } - return accounts.map(({ user_accounts }) => ({ - label: user_accounts.name, - value: user_accounts.slug, - image: user_accounts.picture_url, + return accounts.map(({ accounts }) => ({ + label: accounts.name, + value: accounts.slug, + image: accounts.picture_url, })); } - async loadTempUserAccounts() { const { data: accounts, error } = await this.client + .schema('medreport') .from('user_accounts') .select(`name, slug`); @@ -131,6 +135,7 @@ class AccountsApi { */ async getOrder(accountId: string) { const response = await this.client + .schema('medreport') .from('orders') .select('*, items: order_items !inner (*)') .eq('account_id', accountId) @@ -151,6 +156,7 @@ class AccountsApi { */ async getCustomerId(accountId: string) { const response = await this.client + .schema('medreport') .from('billing_customers') .select('customer_id') .eq('account_id', accountId) diff --git a/packages/features/admin/src/components/admin-account-page.tsx b/packages/features/admin/src/components/admin-account-page.tsx index 71f67bc..540a932 100644 --- a/packages/features/admin/src/components/admin-account-page.tsx +++ b/packages/features/admin/src/components/admin-account-page.tsx @@ -3,6 +3,11 @@ import { BadgeX, Ban, ShieldPlus, VenetianMask } from 'lucide-react'; import { Tables } from '@kit/supabase/database'; import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client'; import { getSupabaseServerClient } from '@kit/supabase/server-client'; +import { + AccountInvitationsTable, + AccountMembersTable, + InviteMembersDialogContainer, +} from '@kit/team-accounts/components'; import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert'; import { AppBreadcrumbs } from '@kit/ui/app-breadcrumbs'; import { Badge } from '@kit/ui/badge'; @@ -28,14 +33,8 @@ import { AdminMembersTable } from './admin-members-table'; import { AdminMembershipsTable } from './admin-memberships-table'; import { AdminReactivateUserDialog } from './admin-reactivate-user-dialog'; -import { - AccountInvitationsTable, - AccountMembersTable, - InviteMembersDialogContainer, -} from '@kit/team-accounts/components'; - -type Account = Tables<'accounts'>; -type Membership = Tables<'accounts_memberships'>; +type Account = Tables<{ schema: 'medreport' }, 'accounts'>; +type Membership = Tables<{ schema: 'medreport' }, 'accounts_memberships'>; export function AdminAccountPage(props: { account: Account & { memberships: Membership[] }; @@ -231,6 +230,7 @@ async function SubscriptionsTable(props: { accountId: string }) { const client = getSupabaseServerClient(); const { data: subscription, error } = await client + .schema('medreport') .from('subscriptions') .select('*, subscription_items !inner (*)') .eq('account_id', props.accountId) @@ -372,6 +372,7 @@ async function getMemberships(userId: string) { const client = getSupabaseServerClient(); const memberships = await client + .schema('medreport') .from('accounts_memberships') .select< string, @@ -394,7 +395,7 @@ async function getMemberships(userId: string) { async function getMembers(accountSlug: string) { const client = getSupabaseServerClient(); - const members = await client.rpc('get_account_members', { + const members = await client.schema('medreport').rpc('get_account_members', { account_slug: accountSlug, }); diff --git a/packages/features/admin/src/components/admin-accounts-table.tsx b/packages/features/admin/src/components/admin-accounts-table.tsx index a6ee29e..0cde270 100644 --- a/packages/features/admin/src/components/admin-accounts-table.tsx +++ b/packages/features/admin/src/components/admin-accounts-table.tsx @@ -38,7 +38,7 @@ import { AdminDeleteUserDialog } from './admin-delete-user-dialog'; import { AdminImpersonateUserDialog } from './admin-impersonate-user-dialog'; import { AdminResetPasswordDialog } from './admin-reset-password-dialog'; -type Account = Database['public']['Tables']['accounts']['Row']; +type Account = Database['medreport']['Tables']['accounts']['Row']; const FiltersSchema = z.object({ type: z.enum(['all', 'team', 'personal']), diff --git a/packages/features/admin/src/components/admin-members-table.tsx b/packages/features/admin/src/components/admin-members-table.tsx index d970645..739d011 100644 --- a/packages/features/admin/src/components/admin-members-table.tsx +++ b/packages/features/admin/src/components/admin-members-table.tsx @@ -9,7 +9,7 @@ import { DataTable } from '@kit/ui/enhanced-data-table'; import { ProfileAvatar } from '@kit/ui/profile-avatar'; type Memberships = - Database['public']['Functions']['get_account_members']['Returns'][number]; + Database['medreport']['Functions']['get_account_members']['Returns'][number]; export function AdminMembersTable(props: { members: Memberships[] }) { return ; diff --git a/packages/features/admin/src/components/admin-memberships-table.tsx b/packages/features/admin/src/components/admin-memberships-table.tsx index a9ea2c3..2217eca 100644 --- a/packages/features/admin/src/components/admin-memberships-table.tsx +++ b/packages/features/admin/src/components/admin-memberships-table.tsx @@ -7,7 +7,7 @@ import { ColumnDef } from '@tanstack/react-table'; import { Tables } from '@kit/supabase/database'; import { DataTable } from '@kit/ui/enhanced-data-table'; -type Membership = Tables<'accounts_memberships'> & { +type Membership = Tables<{ schema: 'medreport' }, 'accounts_memberships'> & { account: { id: string; name: string; diff --git a/packages/features/admin/src/lib/server/admin-server-actions.ts b/packages/features/admin/src/lib/server/admin-server-actions.ts index 7da94b9..e648b0b 100644 --- a/packages/features/admin/src/lib/server/admin-server-actions.ts +++ b/packages/features/admin/src/lib/server/admin-server-actions.ts @@ -15,13 +15,13 @@ import { ImpersonateUserSchema, ReactivateUserSchema, } from './schema/admin-actions.schema'; +import { CreateCompanySchema } from './schema/create-company.schema'; import { CreateUserSchema } from './schema/create-user.schema'; import { ResetPasswordSchema } from './schema/reset-password.schema'; import { createAdminAccountsService } from './services/admin-accounts.service'; import { createAdminAuthUserService } from './services/admin-auth-user.service'; -import { adminAction } from './utils/admin-action'; -import { CreateCompanySchema } from './schema/create-company.schema'; import { createCreateCompanyAccountService } from './services/admin-create-company-account.service'; +import { adminAction } from './utils/admin-action'; /** * @name banUserAction @@ -183,12 +183,16 @@ export const createUserAction = adminAction( ); const { error: accountError } = await adminClient + .schema('medreport') .from('accounts') .update({ personal_code: personalCode }) .eq('id', data.user.id); if (accountError) { - logger.error({ accountError }, 'Error inserting personal code to accounts'); + logger.error( + { accountError }, + 'Error inserting personal code to accounts', + ); throw new Error(`Error saving personal code: ${accountError.message}`); } diff --git a/packages/features/admin/src/lib/server/services/admin-accounts.service.ts b/packages/features/admin/src/lib/server/services/admin-accounts.service.ts index 35815e0..e42e0e0 100644 --- a/packages/features/admin/src/lib/server/services/admin-accounts.service.ts +++ b/packages/features/admin/src/lib/server/services/admin-accounts.service.ts @@ -13,6 +13,7 @@ class AdminAccountsService { async deleteAccount(accountId: string) { const { error } = await this.adminClient + .schema('medreport') .from('accounts') .delete() .eq('id', accountId); diff --git a/packages/features/admin/src/lib/server/services/admin-dashboard.service.ts b/packages/features/admin/src/lib/server/services/admin-dashboard.service.ts index d699e76..d05d452 100644 --- a/packages/features/admin/src/lib/server/services/admin-dashboard.service.ts +++ b/packages/features/admin/src/lib/server/services/admin-dashboard.service.ts @@ -30,6 +30,7 @@ export class AdminDashboardService { }; const subscriptionsPromise = this.client + .schema('medreport') .from('subscriptions') .select('*', selectParams) .eq('status', 'active') @@ -47,6 +48,7 @@ export class AdminDashboardService { }); const trialsPromise = this.client + .schema('medreport') .from('subscriptions') .select('*', selectParams) .eq('status', 'trialing') @@ -64,6 +66,7 @@ export class AdminDashboardService { }); const accountsPromise = this.client + .schema('medreport') .from('accounts') .select('*', selectParams) .eq('is_personal_account', true) @@ -81,6 +84,7 @@ export class AdminDashboardService { }); const teamAccountsPromise = this.client + .schema('medreport') .from('accounts') .select('*', selectParams) .eq('is_personal_account', false) diff --git a/packages/features/auth/package.json b/packages/features/auth/package.json index e6f9724..2ca0885 100644 --- a/packages/features/auth/package.json +++ b/packages/features/auth/package.json @@ -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", @@ -34,7 +35,6 @@ "lucide-react": "^0.510.0", "next": "15.3.2", "react-hook-form": "^7.56.3", - "react-i18next": "^15.5.1", "sonner": "^2.0.3" }, "prettier": "@kit/prettier-config", diff --git a/packages/features/auth/src/components/multi-factor-challenge-container.tsx b/packages/features/auth/src/components/multi-factor-challenge-container.tsx index 17f30f4..fb6f930 100644 --- a/packages/features/auth/src/components/multi-factor-challenge-container.tsx +++ b/packages/features/auth/src/components/multi-factor-challenge-container.tsx @@ -47,7 +47,7 @@ export function MultiFactorChallengeContainer({ const verifyMFAChallenge = useVerifyMFAChallenge({ onSuccess: () => { - router.replace(paths.redirectPath); + router.replace('/'); }, }); diff --git a/packages/features/auth/src/components/sign-in-methods-container.tsx b/packages/features/auth/src/components/sign-in-methods-container.tsx index c6d243e..83bda02 100644 --- a/packages/features/auth/src/components/sign-in-methods-container.tsx +++ b/packages/features/auth/src/components/sign-in-methods-container.tsx @@ -55,14 +55,13 @@ export function SignInMethodsContainer(props: { } try { - const { data: hasPersonalCode } = await client.rpc( - 'has_personal_code', - { + const { data: hasConsentPersonalData } = await client + .schema('medreport') + .rpc('has_consent_personal_data', { account_id: userId, - }, - ); + }); - if (hasPersonalCode) { + if (hasConsentPersonalData) { router.replace(props.paths.returnPath); } else { router.replace(props.paths.updateAccount); diff --git a/packages/features/auth/src/server/actions/update-account-actions.ts b/packages/features/auth/src/server/actions/update-account-actions.ts index eb24be0..0efdab8 100644 --- a/packages/features/auth/src/server/actions/update-account-actions.ts +++ b/packages/features/auth/src/server/actions/update-account-actions.ts @@ -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, diff --git a/packages/features/auth/src/server/api.ts b/packages/features/auth/src/server/api.ts index 6c10ca1..30ae995 100644 --- a/packages/features/auth/src/server/api.ts +++ b/packages/features/auth/src/server/api.ts @@ -13,14 +13,23 @@ class AuthApi { constructor(private readonly client: SupabaseClient) {} /** - * @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 + .schema('medreport') + .rpc('has_unseen_membership_confirmation', { + p_user_id: user.id, + }); if (error) { throw error; @@ -43,15 +52,17 @@ class AuthApi { throw new Error('User not authenticated'); } - const { error } = await this.client.rpc('update_account', { - p_name: data.firstName, - p_last_name: data.lastName, - p_personal_code: data.personalCode, - p_phone: data.phone || '', - p_city: data.city || '', - p_has_consent_personal_data: data.userConsent, - p_uid: user.id, - }); + const { error } = await this.client + .schema('medreport') + .rpc('update_account', { + p_name: data.firstName, + p_last_name: data.lastName, + p_personal_code: data.personalCode, + p_phone: data.phone || '', + p_city: data.city || '', + p_has_consent_personal_data: data.userConsent, + p_uid: user.id, + }); if (error) { throw error; @@ -75,12 +86,15 @@ class AuthApi { if (!user) { throw new Error('User not authenticated'); } - console.log('test', user, data); - const response = await this.client.from('account_params').insert({ - account_id: user.id, - height: data.height, - weight: data.weight, - }); + + const response = await this.client + .schema('medreport') + .from('account_params') + .insert({ + account_id: user.id, + height: data.height, + weight: data.weight, + }); if (response.error) { throw response.error; diff --git a/packages/features/medusa-storefront/src/middleware.ts b/packages/features/medusa-storefront/src/middleware.ts index ff4609b..21290da 100644 --- a/packages/features/medusa-storefront/src/middleware.ts +++ b/packages/features/medusa-storefront/src/middleware.ts @@ -1,29 +1,28 @@ -import { HttpTypes } from "@medusajs/types" -import { NextRequest, NextResponse } from "next/server" +import { HttpTypes } from "@medusajs/types"; +import { NextRequest, NextResponse } from "next/server"; -const BACKEND_URL = process.env.MEDUSA_BACKEND_URL -const PUBLISHABLE_API_KEY = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY -const DEFAULT_REGION = process.env.NEXT_PUBLIC_DEFAULT_REGION || "us" +const BACKEND_URL = process.env.MEDUSA_BACKEND_URL; +const PUBLISHABLE_API_KEY = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY; +const DEFAULT_REGION = process.env.NEXT_PUBLIC_DEFAULT_REGION || "us"; const regionMapCache = { regionMap: new Map(), regionMapUpdated: Date.now(), -} +}; async function getRegionMap(cacheId: string) { - const { regionMap, regionMapUpdated } = regionMapCache + const { regionMap, regionMapUpdated } = regionMapCache; if (!BACKEND_URL) { throw new Error( "Middleware.ts: Error fetching regions. Did you set up regions in your Medusa Admin and define a MEDUSA_BACKEND_URL environment variable? Note that the variable is no longer named NEXT_PUBLIC_MEDUSA_BACKEND_URL." - ) + ); } if ( !regionMap.keys().next().value || regionMapUpdated < Date.now() - 3600 * 1000 ) { - console.log("PUBLISHABLE_API_KEY", PUBLISHABLE_API_KEY) // Fetch regions from Medusa. We can't use the JS client here because middleware is running on Edge and the client needs a Node environment. const { regions } = await fetch(`${BACKEND_URL}/store/regions`, { headers: { @@ -35,32 +34,32 @@ async function getRegionMap(cacheId: string) { }, cache: "force-cache", }).then(async (response) => { - const json = await response.json() + const json = await response.json(); if (!response.ok) { - throw new Error(json.message) + throw new Error(json.message); } - return json - }) + return json; + }); if (!regions?.length) { throw new Error( "No regions found. Please set up regions in your Medusa Admin." - ) + ); } // Create a map of country codes to regions. regions.forEach((region: HttpTypes.StoreRegion) => { region.countries?.forEach((c) => { - regionMapCache.regionMap.set(c.iso_2 ?? "", region) - }) - }) + regionMapCache.regionMap.set(c.iso_2 ?? "", region); + }); + }); - regionMapCache.regionMapUpdated = Date.now() + regionMapCache.regionMapUpdated = Date.now(); } - return regionMapCache.regionMap + return regionMapCache.regionMap; } /** @@ -73,30 +72,32 @@ async function getCountryCode( regionMap: Map ) { try { - let countryCode + let countryCode; const vercelCountryCode = request.headers .get("x-vercel-ip-country") - ?.toLowerCase() + ?.toLowerCase(); - const urlCountryCode = request.nextUrl.pathname.split("/")[1]?.toLowerCase() + const urlCountryCode = request.nextUrl.pathname + .split("/")[1] + ?.toLowerCase(); if (urlCountryCode && regionMap.has(urlCountryCode)) { - countryCode = urlCountryCode + countryCode = urlCountryCode; } else if (vercelCountryCode && regionMap.has(vercelCountryCode)) { - countryCode = vercelCountryCode + countryCode = vercelCountryCode; } else if (regionMap.has(DEFAULT_REGION)) { - countryCode = DEFAULT_REGION + countryCode = DEFAULT_REGION; } else if (regionMap.keys().next().value) { - countryCode = regionMap.keys().next().value + countryCode = regionMap.keys().next().value; } - return countryCode + return countryCode; } catch (error) { if (process.env.NODE_ENV === "development") { console.error( "Middleware.ts: Error getting the country code. Did you set up regions in your Medusa Admin and define a MEDUSA_BACKEND_URL environment variable? Note that the variable is no longer named NEXT_PUBLIC_MEDUSA_BACKEND_URL." - ) + ); } } } @@ -105,56 +106,56 @@ async function getCountryCode( * Middleware to handle region selection and onboarding status. */ export async function middleware(request: NextRequest) { - let redirectUrl = request.nextUrl.href + let redirectUrl = request.nextUrl.href; - let response = NextResponse.redirect(redirectUrl, 307) + let response = NextResponse.redirect(redirectUrl, 307); - let cacheIdCookie = request.cookies.get("_medusa_cache_id") + let cacheIdCookie = request.cookies.get("_medusa_cache_id"); - let cacheId = cacheIdCookie?.value || crypto.randomUUID() + let cacheId = cacheIdCookie?.value || crypto.randomUUID(); - const regionMap = await getRegionMap(cacheId) + const regionMap = await getRegionMap(cacheId); - const countryCode = regionMap && (await getCountryCode(request, regionMap)) + const countryCode = regionMap && (await getCountryCode(request, regionMap)); const urlHasCountryCode = - countryCode && request.nextUrl.pathname.split("/")[1].includes(countryCode) + countryCode && request.nextUrl.pathname.split("/")[1].includes(countryCode); // if one of the country codes is in the url and the cache id is set, return next if (urlHasCountryCode && cacheIdCookie) { - return NextResponse.next() + return NextResponse.next(); } // if one of the country codes is in the url and the cache id is not set, set the cache id and redirect if (urlHasCountryCode && !cacheIdCookie) { response.cookies.set("_medusa_cache_id", cacheId, { maxAge: 60 * 60 * 24, - }) + }); - return response + return response; } // check if the url is a static asset if (request.nextUrl.pathname.includes(".")) { - return NextResponse.next() + return NextResponse.next(); } const redirectPath = - request.nextUrl.pathname === "/" ? "" : request.nextUrl.pathname + request.nextUrl.pathname === "/" ? "" : request.nextUrl.pathname; - const queryString = request.nextUrl.search ? request.nextUrl.search : "" + const queryString = request.nextUrl.search ? request.nextUrl.search : ""; // If no country code is set, we redirect to the relevant region. if (!urlHasCountryCode && countryCode) { - redirectUrl = `${request.nextUrl.origin}/${countryCode}${redirectPath}${queryString}` - response = NextResponse.redirect(`${redirectUrl}`, 307) + redirectUrl = `${request.nextUrl.origin}/${countryCode}${redirectPath}${queryString}`; + response = NextResponse.redirect(`${redirectUrl}`, 307); } - return response + return response; } export const config = { matcher: [ "/((?!api|_next/static|_next/image|favicon.ico|images|assets|png|svg|jpg|jpeg|gif|webp).*)", ], -} +}; diff --git a/packages/features/notifications/package.json b/packages/features/notifications/package.json index 2debf14..5355d69 100644 --- a/packages/features/notifications/package.json +++ b/packages/features/notifications/package.json @@ -24,8 +24,7 @@ "@types/react": "19.1.4", "lucide-react": "^0.510.0", "react": "19.1.0", - "react-dom": "19.1.0", - "react-i18next": "^15.5.1" + "react-dom": "19.1.0" }, "prettier": "@kit/prettier-config", "typesVersions": { diff --git a/packages/features/notifications/src/components/index.ts b/packages/features/notifications/src/components/index.ts index 08883b6..ba10a7f 100644 --- a/packages/features/notifications/src/components/index.ts +++ b/packages/features/notifications/src/components/index.ts @@ -1,3 +1,2 @@ export * from './notifications-popover'; export * from './success-notification'; -export * from './update-account-success-notification'; diff --git a/packages/features/notifications/src/components/notifications-popover.tsx b/packages/features/notifications/src/components/notifications-popover.tsx index 96030fc..946dfcb 100644 --- a/packages/features/notifications/src/components/notifications-popover.tsx +++ b/packages/features/notifications/src/components/notifications-popover.tsx @@ -14,7 +14,7 @@ import { cn } from '@kit/ui/utils'; import { useDismissNotification, useFetchNotifications } from '../hooks'; -type Notification = Database['public']['Tables']['notifications']['Row']; +type Notification = Database['medreport']['Tables']['notifications']['Row']; type PartialNotification = Pick< Notification, @@ -121,7 +121,10 @@ export function NotificationsPopover(params: { return ( -