prettier fix
This commit is contained in:
@@ -2,4 +2,4 @@
|
||||
|
||||
@kit/analytics Package provides a simple and consistent API for tracking analytics events in web applications.
|
||||
|
||||
Please refer to the [documentation](https://makerkit.dev/docs/next-supabase-turbo/analytics/analytics-and-events).
|
||||
Please refer to the [documentation](https://makerkit.dev/docs/next-supabase-turbo/analytics/analytics-and-events).
|
||||
|
||||
@@ -6,9 +6,9 @@ Make sure the app installs the `@kit/billing` package before using it.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-app",
|
||||
"dependencies": {
|
||||
"@kit/billing": "*"
|
||||
}
|
||||
"name": "my-app",
|
||||
"dependencies": {
|
||||
"@kit/billing": "*"
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
@@ -25,21 +25,32 @@ export const LineItemSchema = z
|
||||
.describe('Unique identifier for the line item. Defined by the Provider.')
|
||||
.min(1),
|
||||
name: z
|
||||
.string().describe('Name of the line item. Displayed to the user.')
|
||||
.string()
|
||||
.describe('Name of the line item. Displayed to the user.')
|
||||
.min(1),
|
||||
description: z
|
||||
.string().describe('Description of the line item. Displayed to the user and will replace the auto-generated description inferred' +
|
||||
' from the line item. This is useful if you want to provide a more detailed description to the user.')
|
||||
.string()
|
||||
.describe(
|
||||
'Description of the line item. Displayed to the user and will replace the auto-generated description inferred' +
|
||||
' from the line item. This is useful if you want to provide a more detailed description to the user.',
|
||||
)
|
||||
.optional(),
|
||||
cost: z
|
||||
.number().describe('Cost of the line item. Displayed to the user.')
|
||||
.number()
|
||||
.describe('Cost of the line item. Displayed to the user.')
|
||||
.min(0),
|
||||
type: LineItemTypeSchema,
|
||||
unit: z
|
||||
.string().describe('Unit of the line item. Displayed to the user. Example "seat" or "GB"')
|
||||
.string()
|
||||
.describe(
|
||||
'Unit of the line item. Displayed to the user. Example "seat" or "GB"',
|
||||
)
|
||||
.optional(),
|
||||
setupFee: z
|
||||
.number().describe(`Lemon Squeezy only: If true, in addition to the cost, a setup fee will be charged.`)
|
||||
.number()
|
||||
.describe(
|
||||
`Lemon Squeezy only: If true, in addition to the cost, a setup fee will be charged.`,
|
||||
)
|
||||
.positive()
|
||||
.optional(),
|
||||
tiers: z
|
||||
@@ -78,10 +89,12 @@ export const LineItemSchema = z
|
||||
export const PlanSchema = z
|
||||
.object({
|
||||
id: z
|
||||
.string().describe('Unique identifier for the plan. Defined by yourself.')
|
||||
.string()
|
||||
.describe('Unique identifier for the plan. Defined by yourself.')
|
||||
.min(1),
|
||||
name: z
|
||||
.string().describe('Name of the plan. Displayed to the user.')
|
||||
.string()
|
||||
.describe('Name of the plan. Displayed to the user.')
|
||||
.min(1),
|
||||
interval: BillingIntervalSchema.optional(),
|
||||
custom: z.boolean().default(false).optional(),
|
||||
@@ -106,7 +119,10 @@ export const PlanSchema = z
|
||||
},
|
||||
),
|
||||
trialDays: z
|
||||
.number().describe('Number of days for the trial period. Leave empty for no trial.')
|
||||
.number()
|
||||
.describe(
|
||||
'Number of days for the trial period. Leave empty for no trial.',
|
||||
)
|
||||
.positive()
|
||||
.optional(),
|
||||
paymentType: PaymentTypeSchema,
|
||||
@@ -188,34 +204,43 @@ export const PlanSchema = z
|
||||
const ProductSchema = z
|
||||
.object({
|
||||
id: z
|
||||
.string().describe('Unique identifier for the product. Defined by th Provider.')
|
||||
.string()
|
||||
.describe('Unique identifier for the product. Defined by th Provider.')
|
||||
.min(1),
|
||||
name: z
|
||||
.string().describe('Name of the product. Displayed to the user.')
|
||||
.string()
|
||||
.describe('Name of the product. Displayed to the user.')
|
||||
.min(1),
|
||||
description: z
|
||||
.string().describe('Description of the product. Displayed to the user.')
|
||||
.string()
|
||||
.describe('Description of the product. Displayed to the user.')
|
||||
.min(1),
|
||||
currency: z
|
||||
.string().describe('Currency code for the product. Displayed to the user.')
|
||||
.string()
|
||||
.describe('Currency code for the product. Displayed to the user.')
|
||||
.min(3)
|
||||
.max(3),
|
||||
badge: z
|
||||
.string().describe('Badge for the product. Displayed to the user. Example: "Popular"')
|
||||
.string()
|
||||
.describe(
|
||||
'Badge for the product. Displayed to the user. Example: "Popular"',
|
||||
)
|
||||
.optional(),
|
||||
features: z
|
||||
.array(
|
||||
z.string(),
|
||||
).describe('Features of the product. Displayed to the user.')
|
||||
.array(z.string())
|
||||
.describe('Features of the product. Displayed to the user.')
|
||||
.nonempty(),
|
||||
enableDiscountField: z
|
||||
.boolean().describe('Enable discount field for the product in the checkout.')
|
||||
.boolean()
|
||||
.describe('Enable discount field for the product in the checkout.')
|
||||
.optional(),
|
||||
highlighted: z
|
||||
.boolean().describe('Highlight this product. Displayed to the user.')
|
||||
.boolean()
|
||||
.describe('Highlight this product. Displayed to the user.')
|
||||
.optional(),
|
||||
hidden: z
|
||||
.boolean().describe('Hide this product from being displayed to users.')
|
||||
.boolean()
|
||||
.describe('Hide this product from being displayed to users.')
|
||||
.optional(),
|
||||
plans: z.array(PlanSchema),
|
||||
})
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ReportBillingUsageSchema = z.object({
|
||||
id: z.string().describe('The id of the usage record. For Stripe a customer ID, for LS a subscription item ID.'),
|
||||
id: z
|
||||
.string()
|
||||
.describe(
|
||||
'The id of the usage record. For Stripe a customer ID, for LS a subscription item ID.',
|
||||
),
|
||||
eventName: z
|
||||
.string()
|
||||
.describe('The name of the event that triggered the usage')
|
||||
|
||||
@@ -24,9 +24,7 @@ export interface IHandleWebhookEventParams {
|
||||
|
||||
// this method is called when an invoice is paid. We don't have a specific use case for this
|
||||
// but it's extremely common for credit-based systems
|
||||
onInvoicePaid: (
|
||||
subscription: UpsertSubscriptionParams,
|
||||
) => Promise<unknown>;
|
||||
onInvoicePaid: (subscription: UpsertSubscriptionParams) => Promise<unknown>;
|
||||
|
||||
// generic handler for any event
|
||||
onEvent?: (data: unknown) => Promise<unknown>;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Billing - @kit/billing-gateway
|
||||
|
||||
This package is responsible for handling all billing related operations. It is a gateway to the billing service.
|
||||
This package is responsible for handling all billing related operations. It is a gateway to the billing service.
|
||||
|
||||
@@ -107,7 +107,7 @@ function BlurryBackdrop() {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
'bg-background/30 fixed left-0 top-0 w-full backdrop-blur-sm' +
|
||||
'bg-background/30 fixed top-0 left-0 w-full backdrop-blur-sm' +
|
||||
' !m-0 h-full'
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -317,7 +317,7 @@ export function PlanPicker(
|
||||
|
||||
<div
|
||||
className={
|
||||
'flex flex-col gap-y-3 lg:flex-row lg:items-center lg:space-x-4 lg:space-y-0 lg:text-right'
|
||||
'flex flex-col gap-y-3 lg:flex-row lg:items-center lg:space-y-0 lg:space-x-4 lg:text-right'
|
||||
}
|
||||
>
|
||||
<div>
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
This package is responsible for handling all billing related operations using Lemon Squeezy.
|
||||
|
||||
Please refer to the [documentation](https://makerkit.dev/docs/next-supabase-turbo/billing/lemon-squeezy).
|
||||
Please refer to the [documentation](https://makerkit.dev/docs/next-supabase-turbo/billing/lemon-squeezy).
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# Billing / Montonio - @kit/montonio
|
||||
|
||||
This package is responsible for handling all billing related operations using Montonio.
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const MontonioClientEnvSchema = z
|
||||
.object({
|
||||
accessKey: z.string().min(1),
|
||||
});
|
||||
export const MontonioClientEnvSchema = z.object({
|
||||
accessKey: z.string().min(1),
|
||||
});
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const MontonioServerEnvSchema = z
|
||||
.object({
|
||||
secretKey: z
|
||||
.string({
|
||||
error: `Please provide the variable MONTONIO_SECRET_KEY`,
|
||||
})
|
||||
.min(1),
|
||||
apiUrl: z
|
||||
.string({
|
||||
error: `Please provide the variable MONTONIO_API_URL`,
|
||||
})
|
||||
.min(1),
|
||||
});
|
||||
export const MontonioServerEnvSchema = z.object({
|
||||
secretKey: z
|
||||
.string({
|
||||
error: `Please provide the variable MONTONIO_SECRET_KEY`,
|
||||
})
|
||||
.min(1),
|
||||
apiUrl: z
|
||||
.string({
|
||||
error: `Please provide the variable MONTONIO_API_URL`,
|
||||
})
|
||||
.min(1),
|
||||
});
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
import axios, { AxiosError } from 'axios';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
import { MontonioClientEnvSchema } from '../schema/montonio-client-env.schema';
|
||||
import { MontonioServerEnvSchema } from '../schema/montonio-server-env.schema';
|
||||
|
||||
const clientEnv = () => MontonioClientEnvSchema.parse({
|
||||
accessKey: process.env.NEXT_PUBLIC_MONTONIO_ACCESS_KEY,
|
||||
});
|
||||
const clientEnv = () =>
|
||||
MontonioClientEnvSchema.parse({
|
||||
accessKey: process.env.NEXT_PUBLIC_MONTONIO_ACCESS_KEY,
|
||||
});
|
||||
|
||||
const serverEnv = () => MontonioServerEnvSchema.parse({
|
||||
apiUrl: process.env.MONTONIO_API_URL,
|
||||
secretKey: process.env.MONTONIO_SECRET_KEY,
|
||||
});
|
||||
const serverEnv = () =>
|
||||
MontonioServerEnvSchema.parse({
|
||||
apiUrl: process.env.MONTONIO_API_URL,
|
||||
secretKey: process.env.MONTONIO_SECRET_KEY,
|
||||
});
|
||||
|
||||
export class MontonioOrderHandlerService {
|
||||
public async getMontonioPaymentLink({
|
||||
@@ -45,23 +48,27 @@ export class MontonioOrderHandlerService {
|
||||
returnUrl,
|
||||
askAdditionalInfo: false,
|
||||
merchantReference,
|
||||
type: "one_time",
|
||||
type: 'one_time',
|
||||
};
|
||||
const token = jwt.sign(params, secretKey, {
|
||||
algorithm: "HS256",
|
||||
expiresIn: "10m",
|
||||
algorithm: 'HS256',
|
||||
expiresIn: '10m',
|
||||
});
|
||||
|
||||
try {
|
||||
const { data } = await axios.post(`${apiUrl}/api/payment-links`, { data: token });
|
||||
const { data } = await axios.post(`${apiUrl}/api/payment-links`, {
|
||||
data: token,
|
||||
});
|
||||
return data.url;
|
||||
} catch (error) {
|
||||
if (error instanceof AxiosError) {
|
||||
console.error(error.response?.data);
|
||||
}
|
||||
console.error(`Failed to create payment link, params=${JSON.stringify(params)}`, error);
|
||||
throw new Error("Failed to create payment link");
|
||||
console.error(
|
||||
`Failed to create payment link, params=${JSON.stringify(params)}`,
|
||||
error,
|
||||
);
|
||||
throw new Error('Failed to create payment link');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import type { BillingWebhookHandlerService, IHandleWebhookEventParams } from '@kit/billing';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
import type {
|
||||
BillingWebhookHandlerService,
|
||||
IHandleWebhookEventParams,
|
||||
} from '@kit/billing';
|
||||
import { getLogger } from '@kit/shared/logger';
|
||||
import { Database, Enums } from '@kit/supabase/database';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
import { MontonioServerEnvSchema } from '../schema/montonio-server-env.schema';
|
||||
|
||||
type UpsertOrderParams =
|
||||
@@ -10,20 +15,26 @@ type UpsertOrderParams =
|
||||
type BillingProvider = Enums<{ schema: 'medreport' }, 'billing_provider'>;
|
||||
|
||||
interface MontonioOrderToken {
|
||||
uuid: string;
|
||||
accessKey: string;
|
||||
merchantReference: string;
|
||||
merchantReferenceDisplay: string;
|
||||
paymentStatus: 'PAID' | 'FAILED' | 'CANCELLED' | 'PENDING' | 'EXPIRED' | 'REFUNDED';
|
||||
paymentMethod: string;
|
||||
grandTotal: number;
|
||||
currency: string;
|
||||
senderIban?: string;
|
||||
senderName?: string;
|
||||
paymentProviderName?: string;
|
||||
paymentLinkUuid: string;
|
||||
iat: number;
|
||||
exp: number;
|
||||
uuid: string;
|
||||
accessKey: string;
|
||||
merchantReference: string;
|
||||
merchantReferenceDisplay: string;
|
||||
paymentStatus:
|
||||
| 'PAID'
|
||||
| 'FAILED'
|
||||
| 'CANCELLED'
|
||||
| 'PENDING'
|
||||
| 'EXPIRED'
|
||||
| 'REFUNDED';
|
||||
paymentMethod: string;
|
||||
grandTotal: number;
|
||||
currency: string;
|
||||
senderIban?: string;
|
||||
senderName?: string;
|
||||
paymentProviderName?: string;
|
||||
paymentLinkUuid: string;
|
||||
iat: number;
|
||||
exp: number;
|
||||
}
|
||||
|
||||
const { secretKey } = MontonioServerEnvSchema.parse({
|
||||
@@ -39,22 +50,25 @@ export class MontonioWebhookHandlerService
|
||||
|
||||
async verifyWebhookSignature(request: Request) {
|
||||
const logger = await getLogger();
|
||||
|
||||
|
||||
let token: string;
|
||||
try {
|
||||
const url = new URL(request.url);
|
||||
const searchParams = url.searchParams;
|
||||
console.info("searchParams", searchParams, url);
|
||||
console.info('searchParams', searchParams, url);
|
||||
const tokenParam = searchParams.get('order-token') as string | null;
|
||||
if (!tokenParam) {
|
||||
throw new Error('Missing order-token');
|
||||
}
|
||||
token = tokenParam;
|
||||
} catch (error) {
|
||||
logger.error({
|
||||
error,
|
||||
name: this.namespace,
|
||||
}, `Failed to parse Montonio webhook request`);
|
||||
logger.error(
|
||||
{
|
||||
error,
|
||||
name: this.namespace,
|
||||
},
|
||||
`Failed to parse Montonio webhook request`,
|
||||
);
|
||||
throw new Error('Invalid request');
|
||||
}
|
||||
|
||||
@@ -64,24 +78,30 @@ export class MontonioWebhookHandlerService
|
||||
});
|
||||
return decoded as MontonioOrderToken;
|
||||
} catch (error) {
|
||||
logger.error({
|
||||
error,
|
||||
name: this.namespace,
|
||||
}, `Failed to verify Montonio webhook signature`);
|
||||
logger.error(
|
||||
{
|
||||
error,
|
||||
name: this.namespace,
|
||||
},
|
||||
`Failed to verify Montonio webhook signature`,
|
||||
);
|
||||
throw new Error('Invalid signature');
|
||||
}
|
||||
}
|
||||
|
||||
async handleWebhookEvent(
|
||||
event: MontonioOrderToken,
|
||||
params: IHandleWebhookEventParams
|
||||
params: IHandleWebhookEventParams,
|
||||
) {
|
||||
const logger = await getLogger();
|
||||
|
||||
logger.info({
|
||||
name: this.namespace,
|
||||
event,
|
||||
}, `Received Montonio webhook event`);
|
||||
logger.info(
|
||||
{
|
||||
name: this.namespace,
|
||||
event,
|
||||
},
|
||||
`Received Montonio webhook event`,
|
||||
);
|
||||
|
||||
if (event.paymentStatus === 'PAID') {
|
||||
const [accountId] = event.merchantReferenceDisplay.split(':');
|
||||
@@ -101,11 +121,13 @@ export class MontonioWebhookHandlerService
|
||||
return params.onCheckoutSessionCompleted(order);
|
||||
}
|
||||
|
||||
if (event.paymentStatus === 'FAILED' || event.paymentStatus === 'CANCELLED') {
|
||||
if (
|
||||
event.paymentStatus === 'FAILED' ||
|
||||
event.paymentStatus === 'CANCELLED'
|
||||
) {
|
||||
return params.onPaymentFailed(event.uuid);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
This package is responsible for handling all billing related operations using Stripe.
|
||||
|
||||
Please refer to the [documentation](https://makerkit.dev/docs/next-supabase-turbo/billing/stripe).
|
||||
Please refer to the [documentation](https://makerkit.dev/docs/next-supabase-turbo/billing/stripe).
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# CMS - @kit/cms
|
||||
|
||||
CMS abstraction layer for the Makerkit framework.
|
||||
CMS abstraction layer for the Makerkit framework.
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
Implementation of the CMS layer using the Keystatic library.
|
||||
|
||||
Please refer to the [Documentation](https://makerkit.dev/docs/next-supabase-turbo/content/keystatic).
|
||||
Please refer to the [Documentation](https://makerkit.dev/docs/next-supabase-turbo/content/keystatic).
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# CMS/Wordpress - @kit/wordpress
|
||||
|
||||
Please refer to the [documentation](https://makerkit.dev/docs/next-supabase-turbo/content/wordpress).
|
||||
Please refer to the [documentation](https://makerkit.dev/docs/next-supabase-turbo/content/wordpress).
|
||||
|
||||
@@ -31,18 +31,18 @@ services:
|
||||
- WORDPRESS_DB_NAME=wordpress
|
||||
- WORDPRESS_DEBUG=1
|
||||
- WORDPRESS_CONFIG_EXTRA = |
|
||||
define('FS_METHOD', 'direct');
|
||||
/** disable wp core auto update */
|
||||
define('WP_AUTO_UPDATE_CORE', false);
|
||||
|
||||
/** local environment settings */
|
||||
define('WP_CACHE', false);
|
||||
define('ENVIRONMENT', 'local');
|
||||
|
||||
/** force site home url */
|
||||
if(!defined('WP_HOME')) {
|
||||
define('WP_HOME', 'http://localhost');
|
||||
define('WP_SITEURL', WP_HOME);
|
||||
}
|
||||
define('FS_METHOD', 'direct');
|
||||
/** disable wp core auto update */
|
||||
define('WP_AUTO_UPDATE_CORE', false);
|
||||
|
||||
/** local environment settings */
|
||||
define('WP_CACHE', false);
|
||||
define('ENVIRONMENT', 'local');
|
||||
|
||||
/** force site home url */
|
||||
if(!defined('WP_HOME')) {
|
||||
define('WP_HOME', 'http://localhost');
|
||||
define('WP_SITEURL', WP_HOME);
|
||||
}
|
||||
volumes:
|
||||
db_data:
|
||||
db_data:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
This package is responsible for handling webhooks from database changes.
|
||||
|
||||
For example:
|
||||
|
||||
1. when an account is deleted, we handle the cleanup of all related data in the third-party services.
|
||||
2. when a user is invited, we send an email to the user.
|
||||
3. when an account member is added, we update the subscription in the third-party services
|
||||
@@ -21,4 +22,4 @@ WEBHOOK_SENDER_PROVIDER=svix
|
||||
|
||||
For example, you can add [https://docs.svix.com/quickstart]](Swix) as a webhook sender provider that receives webhooks from the database changes and forwards them to your application.
|
||||
|
||||
Svix is not implemented yet.
|
||||
Svix is not implemented yet.
|
||||
|
||||
@@ -6,7 +6,7 @@ const webhooksSecret = z
|
||||
.string({
|
||||
error: `Provide the variable SUPABASE_DB_WEBHOOK_SECRET. This is used to authenticate the webhook event from Supabase.`,
|
||||
})
|
||||
.describe(`The secret used to verify the webhook signature`,)
|
||||
.describe(`The secret used to verify the webhook signature`)
|
||||
.min(1)
|
||||
.parse(process.env.SUPABASE_DB_WEBHOOK_SECRET);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { TFunction } from "i18next";
|
||||
import { Text } from "@react-email/components";
|
||||
import { EmailFooter } from "./footer";
|
||||
import { Text } from '@react-email/components';
|
||||
import { TFunction } from 'i18next';
|
||||
|
||||
import { EmailFooter } from './footer';
|
||||
|
||||
export default function CommonFooter({ t }: { t: TFunction }) {
|
||||
const namespace = 'common';
|
||||
@@ -15,8 +16,12 @@ export default function CommonFooter({ t }: { t: TFunction }) {
|
||||
return (
|
||||
<EmailFooter>
|
||||
{lines.map((line, index) => (
|
||||
<Text key={index} className="text-[16px] leading-[24px] text-[#242424]" dangerouslySetInnerHTML={{ __html: line }} />
|
||||
<Text
|
||||
key={index}
|
||||
className="text-[16px] leading-[24px] text-[#242424]"
|
||||
dangerouslySetInnerHTML={{ __html: line }}
|
||||
/>
|
||||
))}
|
||||
</EmailFooter>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ export async function renderPatientFirstResultsReceivedEmail({
|
||||
</Text>
|
||||
<Text>{t(`${namespace}:p2`)}</Text>
|
||||
<Text>{t(`${namespace}:p3`)}</Text>
|
||||
<Text>{t(`${namespace}:p4`)}</Text>
|
||||
<Text>{t(`${namespace}:p4`)}</Text>
|
||||
<CommonFooter t={t} />
|
||||
</EmailContent>
|
||||
</EmailWrapper>
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
"paragraph2": "We're sorry to see you go. Please note that this action is irreversible, and we'll make sure to delete all of your data from our systems.",
|
||||
"paragraph3": "We thank you again for using {{productName}}.",
|
||||
"paragraph4": "The {{productName}} Team"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"previewText": "All analysis results have been received",
|
||||
"subject": "All patient analysis results have been received",
|
||||
"openOrdersHeading": "Review the results and prepare a summary:",
|
||||
"linkText": "See results",
|
||||
"ifLinksDisabled": "If the link does not work, you can see the results by copying this link into your browser.",
|
||||
"hello": "Hello"
|
||||
}
|
||||
"previewText": "All analysis results have been received",
|
||||
"subject": "All patient analysis results have been received",
|
||||
"openOrdersHeading": "Review the results and prepare a summary:",
|
||||
"linkText": "See results",
|
||||
"ifLinksDisabled": "If the link does not work, you can see the results by copying this link into your browser.",
|
||||
"hello": "Hello"
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
"lines3": "Customer service: <a href=\"tel:+37258871517\">+372 5887 1517</a>",
|
||||
"lines4": "<a href=\"https://www.medreport.ee\">www.medreport.ee</a>"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
"contactPerson": "Contact Person:",
|
||||
"email": "Email:",
|
||||
"phone": "Phone:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"subject": "Doctor's summary has arrived",
|
||||
"previewText": "The doctor has prepared a summary of the test results.",
|
||||
"p1": "The doctor's summary has arrived:",
|
||||
"p2": "It is recommended to have a comprehensive health check-up regularly, at least once a year, if you wish to maintain an active and fulfilling lifestyle.",
|
||||
"p3": "MedReport makes it easy, convenient, and fast to view health data in one place and order health check-ups.",
|
||||
"p4": "SYNLAB customer support phone: 17123"
|
||||
"subject": "Doctor's summary has arrived",
|
||||
"previewText": "The doctor has prepared a summary of the test results.",
|
||||
"p1": "The doctor's summary has arrived:",
|
||||
"p2": "It is recommended to have a comprehensive health check-up regularly, at least once a year, if you wish to maintain an active and fulfilling lifestyle.",
|
||||
"p3": "MedReport makes it easy, convenient, and fast to view health data in one place and order health check-ups.",
|
||||
"p4": "SYNLAB customer support phone: 17123"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"previewText": "First analysis responses received",
|
||||
"subject": "New job - first analysis responses received",
|
||||
"resultsReceivedForOrders": "New job available to claim",
|
||||
"openOrdersHeading": "See here:",
|
||||
"linkText": "See results",
|
||||
"ifLinksDisabled": "If the link does not work, you can see available jobs by copying this link into your browser.",
|
||||
"hello": "Hello,"
|
||||
}
|
||||
"previewText": "First analysis responses received",
|
||||
"subject": "New job - first analysis responses received",
|
||||
"resultsReceivedForOrders": "New job available to claim",
|
||||
"openOrdersHeading": "See here:",
|
||||
"linkText": "See results",
|
||||
"ifLinksDisabled": "If the link does not work, you can see available jobs by copying this link into your browser.",
|
||||
"hello": "Hello,"
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
"joinTeam": "Join {{teamName}}",
|
||||
"copyPasteLink": "or copy and paste this URL into your browser:",
|
||||
"invitationIntendedFor": "This invitation is intended for {{invitedUserEmail}}."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"previewText": "New jobs available",
|
||||
"subject": "Please write a summary",
|
||||
"resultsReceivedForOrders": "Please review the results and write a summary.",
|
||||
"openOrdersHeading": "See here:",
|
||||
"linkText": "Open job {{nr}}",
|
||||
"ifLinksDisabled": "If the links do not work, you can see available jobs by copying this link into your browser.",
|
||||
"hello": "Hello,"
|
||||
}
|
||||
"previewText": "New jobs available",
|
||||
"subject": "Please write a summary",
|
||||
"resultsReceivedForOrders": "Please review the results and write a summary.",
|
||||
"openOrdersHeading": "See here:",
|
||||
"linkText": "Open job {{nr}}",
|
||||
"ifLinksDisabled": "If the links do not work, you can see available jobs by copying this link into your browser.",
|
||||
"hello": "Hello,"
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"subject": "The referral has been sent to the laboratory. Please go to give samples.",
|
||||
"heading": "Thank you for your order!",
|
||||
"previewText": "The referral for tests has been sent to the laboratory.",
|
||||
"p1": "The referral for tests has been sent to the laboratory digitally. Please go to give samples: {{partnerLocation}}.",
|
||||
"p2": "If you are unable to go to the selected location to give samples, you may visit any other sampling point convenient for you - <a href='https://medreport.ee/et/verevotupunktid'>see locations and opening hours</a>.",
|
||||
"p3": "It is recommended to give samples preferably in the morning (before 12:00) and on an empty stomach without drinking or eating (you may drink water).",
|
||||
"p4": "At the sampling point, please choose in the queue system: under <strong>referrals</strong> select <strong>specialist referral</strong>.",
|
||||
"p5": "If you have any additional questions, please do not hesitate to contact us.",
|
||||
"p6": "SYNLAB customer support phone: 17123",
|
||||
"p1Urine": "The tests include a <strong>urine test</strong>. For the urine test, please collect the first morning urine.",
|
||||
"p2Urine": "You can buy a sample container at the pharmacy and bring the sample with you (procedure performed at home), or ask for one at the sampling point (procedure performed in the point’s restroom)."
|
||||
"subject": "The referral has been sent to the laboratory. Please go to give samples.",
|
||||
"heading": "Thank you for your order!",
|
||||
"previewText": "The referral for tests has been sent to the laboratory.",
|
||||
"p1": "The referral for tests has been sent to the laboratory digitally. Please go to give samples: {{partnerLocation}}.",
|
||||
"p2": "If you are unable to go to the selected location to give samples, you may visit any other sampling point convenient for you - <a href='https://medreport.ee/et/verevotupunktid'>see locations and opening hours</a>.",
|
||||
"p3": "It is recommended to give samples preferably in the morning (before 12:00) and on an empty stomach without drinking or eating (you may drink water).",
|
||||
"p4": "At the sampling point, please choose in the queue system: under <strong>referrals</strong> select <strong>specialist referral</strong>.",
|
||||
"p5": "If you have any additional questions, please do not hesitate to contact us.",
|
||||
"p6": "SYNLAB customer support phone: 17123",
|
||||
"p1Urine": "The tests include a <strong>urine test</strong>. For the urine test, please collect the first morning urine.",
|
||||
"p2Urine": "You can buy a sample container at the pharmacy and bring the sample with you (procedure performed at home), or ask for one at the sampling point (procedure performed in the point’s restroom)."
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"subject": "The first ordered test results have arrived",
|
||||
"previewText": "The first test results have arrived.",
|
||||
"p1": "The first test results have arrived:",
|
||||
"p2": "We will send the next notification once all test results have been received in the system.",
|
||||
"p3": "If you have any additional questions, please feel free to contact us.",
|
||||
"p4": "SYNLAB customer support phone: 17123"
|
||||
"subject": "The first ordered test results have arrived",
|
||||
"previewText": "The first test results have arrived.",
|
||||
"p1": "The first test results have arrived:",
|
||||
"p2": "We will send the next notification once all test results have been received in the system.",
|
||||
"p3": "If you have any additional questions, please feel free to contact us.",
|
||||
"p4": "SYNLAB customer support phone: 17123"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"subject": "All ordered test results have arrived. Awaiting doctor's summary.",
|
||||
"previewText": "All test results have arrived.",
|
||||
"p1": "All test results have arrived:",
|
||||
"p2": "We will send the next notification once the doctor's summary has been prepared.",
|
||||
"p3": "SYNLAB customer support phone: 17123"
|
||||
"subject": "All ordered test results have arrived. Awaiting doctor's summary.",
|
||||
"previewText": "All test results have arrived.",
|
||||
"p1": "All test results have arrived:",
|
||||
"p2": "We will send the next notification once the doctor's summary has been prepared.",
|
||||
"p3": "SYNLAB customer support phone: 17123"
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"subject": "Your Medreport order has been placed - {{analysisPackageName}}",
|
||||
"previewText": "Your Medreport order has been placed - {{analysisPackageName}}",
|
||||
"heading": "Your Medreport order has been placed - {{analysisPackageName}}",
|
||||
"hello": "Hello {{personName}},",
|
||||
"lines1": "The order for {{analysisPackageName}} analysis package has been sent to the lab. Please go to the lab to collect the sample: Synlab - {{partnerLocationName}}",
|
||||
"lines2": "<i>If you are unable to go to the lab to collect the sample, you can go to any other suitable collection point - <a href=\"https://medreport.ee/et/verevotupunktid\">view locations and opening hours</a>.</i>",
|
||||
"lines3": "It is recommended to collect the sample in the morning (before 12:00) and not to eat or drink (water can be drunk).",
|
||||
"lines4": "At the collection point, select the order from the queue: the order from the doctor.",
|
||||
"lines5": "If you have any questions, please contact us.",
|
||||
"lines6": "SYNLAB customer service phone: <a href=\"tel:+37217123\">17123</a>"
|
||||
}
|
||||
"subject": "Your Medreport order has been placed - {{analysisPackageName}}",
|
||||
"previewText": "Your Medreport order has been placed - {{analysisPackageName}}",
|
||||
"heading": "Your Medreport order has been placed - {{analysisPackageName}}",
|
||||
"hello": "Hello {{personName}},",
|
||||
"lines1": "The order for {{analysisPackageName}} analysis package has been sent to the lab. Please go to the lab to collect the sample: Synlab - {{partnerLocationName}}",
|
||||
"lines2": "<i>If you are unable to go to the lab to collect the sample, you can go to any other suitable collection point - <a href=\"https://medreport.ee/et/verevotupunktid\">view locations and opening hours</a>.</i>",
|
||||
"lines3": "It is recommended to collect the sample in the morning (before 12:00) and not to eat or drink (water can be drunk).",
|
||||
"lines4": "At the collection point, select the order from the queue: the order from the doctor.",
|
||||
"lines5": "If you have any questions, please contact us.",
|
||||
"lines6": "SYNLAB customer service phone: <a href=\"tel:+37217123\">17123</a>"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"previewText": "Kõik analüüside vastused on saabunud",
|
||||
"subject": "Patsiendi kõikide analüüside vastused on saabunud",
|
||||
"openOrdersHeading": "Vaata tulemusi ja kirjuta kokkuvõte:",
|
||||
"linkText": "Vaata tulemusi",
|
||||
"ifLinksDisabled": "Kui link ei tööta, näed analüüsitulemusi sellelt aadressilt:",
|
||||
"hello": "Tere"
|
||||
}
|
||||
"previewText": "Kõik analüüside vastused on saabunud",
|
||||
"subject": "Patsiendi kõikide analüüside vastused on saabunud",
|
||||
"openOrdersHeading": "Vaata tulemusi ja kirjuta kokkuvõte:",
|
||||
"linkText": "Vaata tulemusi",
|
||||
"ifLinksDisabled": "Kui link ei tööta, näed analüüsitulemusi sellelt aadressilt:",
|
||||
"hello": "Tere"
|
||||
}
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
},
|
||||
"helloName": "Tere, {{name}}",
|
||||
"hello": "Tere"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"subject": "Arsti kokkuvõte on saabunud",
|
||||
"previewText": "Arst on koostanud kokkuvõte analüüsitulemustele.",
|
||||
"p1": "Arsti kokkuvõte on saabunud:",
|
||||
"p2": "Põhjalikul terviseuuringul on soovituslik käia regulaarselt, aga vähemalt üks kord aastas, kui soovite säilitada aktiivset ja täisväärtuslikku elustiili.",
|
||||
"p3": "MedReport aitab lihtsalt, mugavalt ja kiirelt terviseandmeid ühest kohast vaadata ning tellida terviseuuringuid.",
|
||||
"p4": "SYNLAB klienditoe telefon: 17123"
|
||||
}
|
||||
"subject": "Arsti kokkuvõte on saabunud",
|
||||
"previewText": "Arst on koostanud kokkuvõte analüüsitulemustele.",
|
||||
"p1": "Arsti kokkuvõte on saabunud:",
|
||||
"p2": "Põhjalikul terviseuuringul on soovituslik käia regulaarselt, aga vähemalt üks kord aastas, kui soovite säilitada aktiivset ja täisväärtuslikku elustiili.",
|
||||
"p3": "MedReport aitab lihtsalt, mugavalt ja kiirelt terviseandmeid ühest kohast vaadata ning tellida terviseuuringuid.",
|
||||
"p4": "SYNLAB klienditoe telefon: 17123"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"previewText": "Saabusid esimesed analüüside vastused",
|
||||
"subject": "Uus töö - saabusid esimesed analüüside vastused",
|
||||
"resultsReceivedForOrders": "Patsiendile saabusid esimesed analüüside vastused.",
|
||||
"openOrdersHeading": "Vaata siit:",
|
||||
"linkText": "Vaata tulemusi",
|
||||
"ifLinksDisabled": "Kui link ei tööta, näed analüüsitulemusi sellelt aadressilt:",
|
||||
"hello": "Tere"
|
||||
}
|
||||
"previewText": "Saabusid esimesed analüüside vastused",
|
||||
"subject": "Uus töö - saabusid esimesed analüüside vastused",
|
||||
"resultsReceivedForOrders": "Patsiendile saabusid esimesed analüüside vastused.",
|
||||
"openOrdersHeading": "Vaata siit:",
|
||||
"linkText": "Vaata tulemusi",
|
||||
"ifLinksDisabled": "Kui link ei tööta, näed analüüsitulemusi sellelt aadressilt:",
|
||||
"hello": "Tere"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"previewText": "Palun koosta kokkuvõte",
|
||||
"subject": "Palun koosta kokkuvõte",
|
||||
"resultsReceivedForOrders": "Palun vaata tulemused üle ja kirjuta kokkuvõte.",
|
||||
"openOrdersHeading": "Vaata siit:",
|
||||
"linkText": "Töö {{nr}}",
|
||||
"ifLinksDisabled": "Kui lingid ei tööta, näed vabasid töid sellelt aadressilt:",
|
||||
"hello": "Tere"
|
||||
}
|
||||
"previewText": "Palun koosta kokkuvõte",
|
||||
"subject": "Palun koosta kokkuvõte",
|
||||
"resultsReceivedForOrders": "Palun vaata tulemused üle ja kirjuta kokkuvõte.",
|
||||
"openOrdersHeading": "Vaata siit:",
|
||||
"linkText": "Töö {{nr}}",
|
||||
"ifLinksDisabled": "Kui lingid ei tööta, näed vabasid töid sellelt aadressilt:",
|
||||
"hello": "Tere"
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"subject": "Saatekiri on saadetud laborisse. Palun mine proove andma.",
|
||||
"heading": "Täname tellimuse eest!",
|
||||
"previewText": "Saatekiri uuringute tegemiseks on saadetud laborisse.",
|
||||
"p1": "Saatekiri uuringute tegemiseks on saadetud laborisse digitaalselt. Palun mine proove andma: {{partnerLocation}}.",
|
||||
"p2": "Kui Teil ei ole võimalik valitud asukohta minna proove andma, siis võite minna endale sobivasse proovivõtupunkti - <a href='https://medreport.ee/et/verevotupunktid'>vaata asukohti ja lahtiolekuaegasid</a>.",
|
||||
"p3": "Soovituslik on proove anda pigem hommikul (enne 12:00) ning söömata ja joomata (vett võib juua).",
|
||||
"p4": "Proovivõtupunktis valige järjekorrasüsteemis: <strong>saatekirjad</strong> alt <strong>eriarsti saatekiri</strong>",
|
||||
"p5": "Juhul kui tekkis lisaküsimusi, siis võtke julgelt ühendust.",
|
||||
"p6": "SYNLAB klienditoe telefon: 17123",
|
||||
"p1Urine": "Analüüsides on ette nähtud <strong>uriinianalüüs</strong>. Uriinianalüüsiks võta hommikune esmane uriin.",
|
||||
"p2Urine": "Proovitopsi võib soetada apteegist ja analüüsi kaasa võtta (teostada protseduur kodus) või küsida proovivõtupunktist (teostada protseduur proovipunkti wc-s)."
|
||||
}
|
||||
"subject": "Saatekiri on saadetud laborisse. Palun mine proove andma.",
|
||||
"heading": "Täname tellimuse eest!",
|
||||
"previewText": "Saatekiri uuringute tegemiseks on saadetud laborisse.",
|
||||
"p1": "Saatekiri uuringute tegemiseks on saadetud laborisse digitaalselt. Palun mine proove andma: {{partnerLocation}}.",
|
||||
"p2": "Kui Teil ei ole võimalik valitud asukohta minna proove andma, siis võite minna endale sobivasse proovivõtupunkti - <a href='https://medreport.ee/et/verevotupunktid'>vaata asukohti ja lahtiolekuaegasid</a>.",
|
||||
"p3": "Soovituslik on proove anda pigem hommikul (enne 12:00) ning söömata ja joomata (vett võib juua).",
|
||||
"p4": "Proovivõtupunktis valige järjekorrasüsteemis: <strong>saatekirjad</strong> alt <strong>eriarsti saatekiri</strong>",
|
||||
"p5": "Juhul kui tekkis lisaküsimusi, siis võtke julgelt ühendust.",
|
||||
"p6": "SYNLAB klienditoe telefon: 17123",
|
||||
"p1Urine": "Analüüsides on ette nähtud <strong>uriinianalüüs</strong>. Uriinianalüüsiks võta hommikune esmane uriin.",
|
||||
"p2Urine": "Proovitopsi võib soetada apteegist ja analüüsi kaasa võtta (teostada protseduur kodus) või küsida proovivõtupunktist (teostada protseduur proovipunkti wc-s)."
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"subject": "Saabusid tellitud uuringute esimesed tulemused",
|
||||
"previewText": "Esimesed uuringute tulemused on saabunud.",
|
||||
"p1": "Esimesed uuringute tulemused on saabunud:",
|
||||
"p2": "Saadame järgmise teavituse, kui kõik uuringute vastused on saabunud süsteemi.",
|
||||
"p3": "Juhul kui tekkis lisaküsimusi, siis võtke julgelt ühendust.",
|
||||
"p4": "SYNLAB klienditoe telefon: 17123"
|
||||
}
|
||||
"subject": "Saabusid tellitud uuringute esimesed tulemused",
|
||||
"previewText": "Esimesed uuringute tulemused on saabunud.",
|
||||
"p1": "Esimesed uuringute tulemused on saabunud:",
|
||||
"p2": "Saadame järgmise teavituse, kui kõik uuringute vastused on saabunud süsteemi.",
|
||||
"p3": "Juhul kui tekkis lisaküsimusi, siis võtke julgelt ühendust.",
|
||||
"p4": "SYNLAB klienditoe telefon: 17123"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"subject": "Kõikide tellitud uuringute tulemused on saabunud. Ootab arsti kokkuvõtet.",
|
||||
"previewText": "Kõikide uuringute tulemused on saabunud.",
|
||||
"p1": "Kõikide uuringute tulemused on saabunud:",
|
||||
"p2": "Saadame järgmise teavituse kui arsti kokkuvõte on koostatud.",
|
||||
"p3": "SYNLAB klienditoe telefon: 17123"
|
||||
}
|
||||
"subject": "Kõikide tellitud uuringute tulemused on saabunud. Ootab arsti kokkuvõtet.",
|
||||
"previewText": "Kõikide uuringute tulemused on saabunud.",
|
||||
"p1": "Kõikide uuringute tulemused on saabunud:",
|
||||
"p2": "Saadame järgmise teavituse kui arsti kokkuvõte on koostatud.",
|
||||
"p3": "SYNLAB klienditoe telefon: 17123"
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"subject": "Teie Medreport tellimus on kinnitatud - {{analysisPackageName}}",
|
||||
"previewText": "Teie Medreport tellimus on kinnitatud - {{analysisPackageName}}",
|
||||
"heading": "Teie Medreport tellimus on kinnitatud - {{analysisPackageName}}",
|
||||
"hello": "Tere {{personName}},",
|
||||
"lines1": "Saatekiri {{analysisPackageName}} analüüsi uuringuteks on saadetud laborisse digitaalselt. Palun mine proove andma: Synlab - {{partnerLocationName}}",
|
||||
"lines2": "<i>Kui Teil ei ole võimalik valitud asukohta minna proove andma, siis võite minna endale sobivasse proovivõtupunkti - <a href=\"https://medreport.ee/et/verevotupunktid\">vaata asukohti ja lahtiolekuaegasid</a>.</i>",
|
||||
"lines3": "Soovituslik on proove anda pigem hommikul (enne 12:00) ning söömata ja joomata (vett võib juua).",
|
||||
"lines4": "Proovivõtupunktis valige järjekorrasüsteemis: <strong>saatekirjad</strong> alt <strong>eriarsti saatekiri</strong>.",
|
||||
"lines5": "Juhul kui tekkis lisaküsimusi, siis võtke julgelt ühendust.",
|
||||
"lines6": "SYNLAB klienditoe telefon: <a href=\"tel:+37217123\">17123</a>"
|
||||
}
|
||||
"subject": "Teie Medreport tellimus on kinnitatud - {{analysisPackageName}}",
|
||||
"previewText": "Teie Medreport tellimus on kinnitatud - {{analysisPackageName}}",
|
||||
"heading": "Teie Medreport tellimus on kinnitatud - {{analysisPackageName}}",
|
||||
"hello": "Tere {{personName}},",
|
||||
"lines1": "Saatekiri {{analysisPackageName}} analüüsi uuringuteks on saadetud laborisse digitaalselt. Palun mine proove andma: Synlab - {{partnerLocationName}}",
|
||||
"lines2": "<i>Kui Teil ei ole võimalik valitud asukohta minna proove andma, siis võite minna endale sobivasse proovivõtupunkti - <a href=\"https://medreport.ee/et/verevotupunktid\">vaata asukohti ja lahtiolekuaegasid</a>.</i>",
|
||||
"lines3": "Soovituslik on proove anda pigem hommikul (enne 12:00) ning söömata ja joomata (vett võib juua).",
|
||||
"lines4": "Proovivõtupunktis valige järjekorrasüsteemis: <strong>saatekirjad</strong> alt <strong>eriarsti saatekiri</strong>.",
|
||||
"lines5": "Juhul kui tekkis lisaküsimusi, siis võtke julgelt ühendust.",
|
||||
"lines6": "SYNLAB klienditoe telefon: <a href=\"tel:+37217123\">17123</a>"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"previewText": "All analysis results have been received",
|
||||
"subject": "All patient analysis results have been received",
|
||||
"openOrdersHeading": "Review the results and prepare a summary:",
|
||||
"linkText": "See results",
|
||||
"ifLinksDisabled": "If the link does not work, you can see the results by copying this link into your browser.",
|
||||
"hello": "Hello"
|
||||
}
|
||||
"previewText": "All analysis results have been received",
|
||||
"subject": "All patient analysis results have been received",
|
||||
"openOrdersHeading": "Review the results and prepare a summary:",
|
||||
"linkText": "See results",
|
||||
"ifLinksDisabled": "If the link does not work, you can see the results by copying this link into your browser.",
|
||||
"hello": "Hello"
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
"lines3": "Служба поддержки: <a href=\"tel:+37258871517\">+372 5887 1517</a>",
|
||||
"lines4": "<a href=\"https://www.medreport.ee\">www.medreport.ee</a>"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
"contactPerson": "Контактное лицо:",
|
||||
"email": "Электронная почта:",
|
||||
"phone": "Телефон:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"subject": "Заключение врача готово",
|
||||
"previewText": "Врач подготовил заключение по результатам анализов.",
|
||||
"p1": "Заключение врача готово:",
|
||||
"p2": "Рекомендуется проходить комплексное обследование регулярно, но как минимум один раз в год, если вы хотите сохранить активный и полноценный образ жизни.",
|
||||
"p3": "MedReport позволяет легко, удобно и быстро просматривать медицинские данные в одном месте и заказывать обследования.",
|
||||
"p4": "Телефон службы поддержки SYNLAB: 17123"
|
||||
}
|
||||
"subject": "Заключение врача готово",
|
||||
"previewText": "Врач подготовил заключение по результатам анализов.",
|
||||
"p1": "Заключение врача готово:",
|
||||
"p2": "Рекомендуется проходить комплексное обследование регулярно, но как минимум один раз в год, если вы хотите сохранить активный и полноценный образ жизни.",
|
||||
"p3": "MedReport позволяет легко, удобно и быстро просматривать медицинские данные в одном месте и заказывать обследования.",
|
||||
"p4": "Телефон службы поддержки SYNLAB: 17123"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"previewText": "First analysis responses received",
|
||||
"subject": "New job - first analysis responses received",
|
||||
"resultsReceivedForOrders": "New job available to claim",
|
||||
"openOrdersHeading": "See here:",
|
||||
"linkText": "See results",
|
||||
"ifLinksDisabled": "If the link does not work, you can see the results by copying this link into your browser.",
|
||||
"hello": "Hello,"
|
||||
}
|
||||
"previewText": "First analysis responses received",
|
||||
"subject": "New job - first analysis responses received",
|
||||
"resultsReceivedForOrders": "New job available to claim",
|
||||
"openOrdersHeading": "See here:",
|
||||
"linkText": "See results",
|
||||
"ifLinksDisabled": "If the link does not work, you can see the results by copying this link into your browser.",
|
||||
"hello": "Hello,"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"previewText": "New jobs available",
|
||||
"subject": "Please write a summary",
|
||||
"resultsReceivedForOrders": "Please review the results and write a summary.",
|
||||
"openOrdersHeading": "See here:",
|
||||
"linkText": "Open job {{nr}}",
|
||||
"ifLinksDisabled": "If the links do not work, you can see available jobs by copying this link into your browser.",
|
||||
"hello": "Hello,"
|
||||
}
|
||||
"previewText": "New jobs available",
|
||||
"subject": "Please write a summary",
|
||||
"resultsReceivedForOrders": "Please review the results and write a summary.",
|
||||
"openOrdersHeading": "See here:",
|
||||
"linkText": "Open job {{nr}}",
|
||||
"ifLinksDisabled": "If the links do not work, you can see available jobs by copying this link into your browser.",
|
||||
"hello": "Hello,"
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"subject": "Направление отправлено в лабораторию. Пожалуйста, сдайте анализы.",
|
||||
"heading": "Спасибо за заказ!",
|
||||
"previewText": "Направление на обследование отправлено в лабораторию.",
|
||||
"p1": "Направление на обследование было отправлено в лабораторию в цифровом виде. Пожалуйста, сдайте анализы: {{partnerLocation}}.",
|
||||
"p2": "Если у вас нет возможности прийти в выбранный пункт сдачи анализов, вы можете обратиться в любой удобный для вас пункт – <a href='https://medreport.ee/et/verevotupunktid'>посмотреть адреса и часы работы</a>.",
|
||||
"p3": "Рекомендуется сдавать анализы утром (до 12:00) натощак, без еды и напитков (разрешается пить воду).",
|
||||
"p4": "В пункте сдачи анализов выберите в системе очереди: в разделе <strong>направления</strong> → <strong>направление от специалиста</strong>.",
|
||||
"p5": "Если у вас возникли дополнительные вопросы, пожалуйста, свяжитесь с нами.",
|
||||
"p6": "Телефон службы поддержки SYNLAB: 17123",
|
||||
"p1Urine": "В обследование входит <strong>анализ мочи</strong>. Для анализа необходимо собрать первую утреннюю мочу.",
|
||||
"p2Urine": "Контейнер можно приобрести в аптеке и принести образец с собой (процедура проводится дома) или взять контейнер в пункте сдачи (процедура проводится в туалете пункта)."
|
||||
"subject": "Направление отправлено в лабораторию. Пожалуйста, сдайте анализы.",
|
||||
"heading": "Спасибо за заказ!",
|
||||
"previewText": "Направление на обследование отправлено в лабораторию.",
|
||||
"p1": "Направление на обследование было отправлено в лабораторию в цифровом виде. Пожалуйста, сдайте анализы: {{partnerLocation}}.",
|
||||
"p2": "Если у вас нет возможности прийти в выбранный пункт сдачи анализов, вы можете обратиться в любой удобный для вас пункт – <a href='https://medreport.ee/et/verevotupunktid'>посмотреть адреса и часы работы</a>.",
|
||||
"p3": "Рекомендуется сдавать анализы утром (до 12:00) натощак, без еды и напитков (разрешается пить воду).",
|
||||
"p4": "В пункте сдачи анализов выберите в системе очереди: в разделе <strong>направления</strong> → <strong>направление от специалиста</strong>.",
|
||||
"p5": "Если у вас возникли дополнительные вопросы, пожалуйста, свяжитесь с нами.",
|
||||
"p6": "Телефон службы поддержки SYNLAB: 17123",
|
||||
"p1Urine": "В обследование входит <strong>анализ мочи</strong>. Для анализа необходимо собрать первую утреннюю мочу.",
|
||||
"p2Urine": "Контейнер можно приобрести в аптеке и принести образец с собой (процедура проводится дома) или взять контейнер в пункте сдачи (процедура проводится в туалете пункта)."
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"subject": "Поступили первые результаты заказанных исследований",
|
||||
"previewText": "Первые результаты исследований поступили.",
|
||||
"p1": "Первые результаты исследований поступили:",
|
||||
"p2": "Мы отправим следующее уведомление, когда все результаты исследований будут получены в системе.",
|
||||
"p3": "Если у вас возникнут дополнительные вопросы, пожалуйста, свяжитесь с нами.",
|
||||
"p4": "Телефон службы поддержки SYNLAB: 17123"
|
||||
"subject": "Поступили первые результаты заказанных исследований",
|
||||
"previewText": "Первые результаты исследований поступили.",
|
||||
"p1": "Первые результаты исследований поступили:",
|
||||
"p2": "Мы отправим следующее уведомление, когда все результаты исследований будут получены в системе.",
|
||||
"p3": "Если у вас возникнут дополнительные вопросы, пожалуйста, свяжитесь с нами.",
|
||||
"p4": "Телефон службы поддержки SYNLAB: 17123"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"subject": "Все заказанные результаты исследований поступили. Ожидается заключение врача.",
|
||||
"previewText": "Все результаты исследований поступили.",
|
||||
"p1": "Все результаты исследований поступили:",
|
||||
"p2": "Мы отправим следующее уведомление, когда заключение врача будет подготовлено.",
|
||||
"p3": "Телефон службы поддержки SYNLAB: 17123"
|
||||
}
|
||||
"subject": "Все заказанные результаты исследований поступили. Ожидается заключение врача.",
|
||||
"previewText": "Все результаты исследований поступили.",
|
||||
"p1": "Все результаты исследований поступили:",
|
||||
"p2": "Мы отправим следующее уведомление, когда заключение врача будет подготовлено.",
|
||||
"p3": "Телефон службы поддержки SYNLAB: 17123"
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"subject": "Ваш заказ Medreport подтвержден - {{analysisPackageName}}",
|
||||
"previewText": "Ваш заказ Medreport подтвержден - {{analysisPackageName}}",
|
||||
"heading": "Ваш заказ Medreport подтвержден - {{analysisPackageName}}",
|
||||
"hello": "Здравствуйте, {{personName}},",
|
||||
"lines1": "Направление на исследование {{analysisPackageName}} было отправлено в лабораторию в цифровом виде. Пожалуйста, сдайте анализы: Synlab - {{partnerLocationName}}",
|
||||
"lines2": "<i>Если вы не можете посетить выбранный пункт сдачи анализов, вы можете обратиться в удобный для вас пункт - <a href=\"https://medreport.ee/et/verevotupunktid\">посмотреть адреса и часы работы</a>.</i>",
|
||||
"lines3": "Рекомендуется сдавать анализы утром (до 12:00) натощак (можно пить воду).",
|
||||
"lines4": "В пункте сдачи анализов выберите в системе очереди: <strong>направления</strong> -> <strong>направление от специалиста</strong>.",
|
||||
"lines5": "Если у вас возникнут дополнительные вопросы, смело свяжитесь с нами.",
|
||||
"lines6": "Телефон службы поддержки SYNLAB: <a href=\"tel:+37217123\">17123</a>"
|
||||
}
|
||||
"subject": "Ваш заказ Medreport подтвержден - {{analysisPackageName}}",
|
||||
"previewText": "Ваш заказ Medreport подтвержден - {{analysisPackageName}}",
|
||||
"heading": "Ваш заказ Medreport подтвержден - {{analysisPackageName}}",
|
||||
"hello": "Здравствуйте, {{personName}},",
|
||||
"lines1": "Направление на исследование {{analysisPackageName}} было отправлено в лабораторию в цифровом виде. Пожалуйста, сдайте анализы: Synlab - {{partnerLocationName}}",
|
||||
"lines2": "<i>Если вы не можете посетить выбранный пункт сдачи анализов, вы можете обратиться в удобный для вас пункт - <a href=\"https://medreport.ee/et/verevotupunktid\">посмотреть адреса и часы работы</a>.</i>",
|
||||
"lines3": "Рекомендуется сдавать анализы утром (до 12:00) натощак (можно пить воду).",
|
||||
"lines4": "В пункте сдачи анализов выберите в системе очереди: <strong>направления</strong> -> <strong>направление от специалиста</strong>.",
|
||||
"lines5": "Если у вас возникнут дополнительные вопросы, смело свяжитесь с нами.",
|
||||
"lines6": "Телефон службы поддержки SYNLAB: <a href=\"tel:+37217123\">17123</a>"
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ export function AccountSelector({
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
className={cn(
|
||||
'dark:shadow-primary/10 group w-full min-w-0 px-4 py-2 h-10 border-1 lg:w-auto lg:max-w-fit',
|
||||
'dark:shadow-primary/10 group h-10 w-full min-w-0 border-1 px-4 py-2 lg:w-auto lg:max-w-fit',
|
||||
{
|
||||
'justify-start': !collapsed,
|
||||
'm-auto justify-center px-4 lg:w-full': collapsed,
|
||||
@@ -124,7 +124,7 @@ export function AccountSelector({
|
||||
condition={selected}
|
||||
fallback={
|
||||
<span
|
||||
className={cn('flex max-w-full items-center size-4', {
|
||||
className={cn('flex size-4 max-w-full items-center', {
|
||||
'justify-center gap-x-0': collapsed,
|
||||
'gap-x-4': !collapsed,
|
||||
})}
|
||||
@@ -148,7 +148,7 @@ export function AccountSelector({
|
||||
'gap-x-4': !collapsed,
|
||||
})}
|
||||
>
|
||||
<Avatar className={'rounded-md size-6'}>
|
||||
<Avatar className={'size-6 rounded-md'}>
|
||||
<AvatarImage src={account.image ?? undefined} />
|
||||
|
||||
<AvatarFallback
|
||||
@@ -233,7 +233,7 @@ export function AccountSelector({
|
||||
}}
|
||||
>
|
||||
<div className={'flex items-center'}>
|
||||
<Avatar className={'rounded-xs mr-2 h-6 w-6'}>
|
||||
<Avatar className={'mr-2 h-6 w-6 rounded-xs'}>
|
||||
<AvatarImage src={account.image ?? undefined} />
|
||||
|
||||
<AvatarFallback
|
||||
@@ -297,7 +297,7 @@ export function AccountSelector({
|
||||
|
||||
function UserAvatar(props: { pictureUrl?: string }) {
|
||||
return (
|
||||
<Avatar className={'rounded-md size-6'}>
|
||||
<Avatar className={'size-6 rounded-md'}>
|
||||
<AvatarImage src={props.pictureUrl} />
|
||||
</Avatar>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from './user-workspace-context';
|
||||
export * from './personal-account-settings/mfa/multi-factor-auth-list'
|
||||
export * from './personal-account-settings/mfa/multi-factor-auth-setup-dialog'
|
||||
export * from './personal-account-settings/mfa/multi-factor-auth-list';
|
||||
export * from './personal-account-settings/mfa/multi-factor-auth-setup-dialog';
|
||||
|
||||
@@ -81,7 +81,8 @@ export function PersonalAccountDropdown({
|
||||
|
||||
const { name, last_name } = personalAccountData ?? {};
|
||||
const firstNameLabel = toTitleCase(name) ?? '-';
|
||||
const fullNameLabel = name && last_name ? toTitleCase(`${name} ${last_name}`) : '-';
|
||||
const fullNameLabel =
|
||||
name && last_name ? toTitleCase(`${name} ${last_name}`) : '-';
|
||||
|
||||
const hasTotpFactor = useMemo(() => {
|
||||
const factors = user?.factors ?? [];
|
||||
|
||||
@@ -347,9 +347,7 @@ function FactorQrCode({
|
||||
<QrImage src={form.getValues('qrCode')} />
|
||||
</div>
|
||||
|
||||
<p className='text-center text-sm'>
|
||||
{form.getValues('totpSecret')}
|
||||
</p>
|
||||
<p className="text-center text-sm">{form.getValues('totpSecret')}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
import { Database } from '@kit/supabase/database';
|
||||
|
||||
import PersonalCode from '~/lib/utils';
|
||||
|
||||
import { AccountWithParams } from '../types/accounts';
|
||||
@@ -11,7 +12,7 @@ import { AccountWithParams } from '../types/accounts';
|
||||
* @param {SupabaseClient<Database>} client - The Supabase client instance.
|
||||
*/
|
||||
class AccountsApi {
|
||||
constructor(private readonly client: SupabaseClient<Database>) { }
|
||||
constructor(private readonly client: SupabaseClient<Database>) {}
|
||||
|
||||
/**
|
||||
* @name getAccount
|
||||
|
||||
@@ -11,13 +11,13 @@ export enum ApplicationRoleEnum {
|
||||
export type AccountWithParams =
|
||||
Database['medreport']['Tables']['accounts']['Row'] & {
|
||||
accountParams:
|
||||
| (Pick<
|
||||
Database['medreport']['Tables']['account_params']['Row'],
|
||||
'weight' | 'height'
|
||||
> & {
|
||||
isSmoker:
|
||||
| Database['medreport']['Tables']['account_params']['Row']['is_smoker']
|
||||
| (Pick<
|
||||
Database['medreport']['Tables']['account_params']['Row'],
|
||||
'weight' | 'height'
|
||||
> & {
|
||||
isSmoker:
|
||||
| Database['medreport']['Tables']['account_params']['Row']['is_smoker']
|
||||
| null;
|
||||
})
|
||||
| null;
|
||||
})
|
||||
| null;
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ export function AdminCreateUserDialog(props: React.PropsWithChildren) {
|
||||
email: '',
|
||||
password: '',
|
||||
emailConfirm: false,
|
||||
personalCode: ''
|
||||
personalCode: '',
|
||||
},
|
||||
mode: 'onBlur',
|
||||
});
|
||||
@@ -163,7 +163,7 @@ export function AdminCreateUserDialog(props: React.PropsWithChildren) {
|
||||
<FormField
|
||||
name={'emailConfirm'}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-row items-start space-x-3 space-y-0 rounded-md border p-4">
|
||||
<FormItem className="flex flex-row items-start space-y-0 space-x-3 rounded-md border p-4">
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={field.value}
|
||||
|
||||
@@ -148,12 +148,17 @@ export const deleteAccountAction = adminAction(
|
||||
}
|
||||
const medusa = getAdminSdk();
|
||||
const { customer_groups } = await medusa.admin.customerGroup.list();
|
||||
const customerGroup = customer_groups.find(({ name }) => name === customerGroupName);
|
||||
const customerGroup = customer_groups.find(
|
||||
({ name }) => name === customerGroupName,
|
||||
);
|
||||
if (customerGroup) {
|
||||
try {
|
||||
await medusa.admin.customerGroup.delete(customerGroup.id);
|
||||
} catch (e) {
|
||||
logger.error({ accountId }, `Error deleting Medusa customer group for company ${customerGroupName}`);
|
||||
logger.error(
|
||||
{ accountId },
|
||||
`Error deleting Medusa customer group for company ${customerGroupName}`,
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -288,22 +293,29 @@ export const createCompanyAccountAction = enhanceAction(
|
||||
|
||||
logger.info(ctx, `Creating Medusa customer group`);
|
||||
const medusa = getAdminSdk();
|
||||
const { customer_groups: existingCustomerGroups } = await medusa.admin.customerGroup.list();
|
||||
const isExisting = existingCustomerGroups.find((group) => group.name === name);
|
||||
const { customer_groups: existingCustomerGroups } =
|
||||
await medusa.admin.customerGroup.list();
|
||||
const isExisting = existingCustomerGroups.find(
|
||||
(group) => group.name === name,
|
||||
);
|
||||
if (isExisting) {
|
||||
logger.info(ctx, `Customer group already exists`);
|
||||
} else {
|
||||
logger.info(ctx, `Creating Medusa customer group`);
|
||||
const { data: account } = await client
|
||||
.schema('medreport').from('accounts')
|
||||
.schema('medreport')
|
||||
.from('accounts')
|
||||
.select('medusa_account_id')
|
||||
.eq('personal_code', ownerPersonalCode)
|
||||
.single().throwOnError();
|
||||
.single()
|
||||
.throwOnError();
|
||||
const medusaAccountId = account.medusa_account_id;
|
||||
if (!medusaAccountId) {
|
||||
logger.error(ctx, `User has no Medusa account ID`);
|
||||
} else {
|
||||
const { customer_group: { id: customerGroupId } } = await medusa.admin.customerGroup.create({ name });
|
||||
const {
|
||||
customer_group: { id: customerGroupId },
|
||||
} = await medusa.admin.customerGroup.create({ name });
|
||||
const { customers } = await medusa.admin.customer.list({
|
||||
id: medusaAccountId,
|
||||
});
|
||||
@@ -316,7 +328,6 @@ export const createCompanyAccountAction = enhanceAction(
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
redirect(`/admin/accounts/${data.id}`);
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const CreateUserProfileSchema = z.object({
|
||||
personalCode: z.string().regex(/^[1-6]\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}\d$/, {
|
||||
message: 'Invalid Estonian personal code format',
|
||||
}),
|
||||
personalCode: z
|
||||
.string()
|
||||
.regex(/^[1-6]\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}\d$/, {
|
||||
message: 'Invalid Estonian personal code format',
|
||||
}),
|
||||
});
|
||||
|
||||
export type CreateUserProfileSchemaType = z.infer<typeof CreateUserProfileSchema>;
|
||||
|
||||
export type CreateUserProfileSchemaType = z.infer<
|
||||
typeof CreateUserProfileSchema
|
||||
>;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const CreateUserSchema = z.object({
|
||||
personalCode: z.string().regex(/^[1-6]\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}\d$/, {
|
||||
message: 'Invalid Estonian personal code format',
|
||||
}),
|
||||
personalCode: z
|
||||
.string()
|
||||
.regex(/^[1-6]\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}\d$/, {
|
||||
message: 'Invalid Estonian personal code format',
|
||||
}),
|
||||
email: z.string().email({ message: 'Please enter a valid email address' }),
|
||||
password: z
|
||||
.string()
|
||||
|
||||
@@ -44,7 +44,8 @@ class AdminAccountsService {
|
||||
.from('accounts')
|
||||
.select('*')
|
||||
.eq('id', accountId)
|
||||
.single().throwOnError();
|
||||
.single()
|
||||
.throwOnError();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import Medusa from "@medusajs/js-sdk"
|
||||
import Medusa from '@medusajs/js-sdk';
|
||||
|
||||
export const getAdminSdk = () => {
|
||||
const medusaBackendUrl = process.env.MEDUSA_BACKEND_PUBLIC_URL!;
|
||||
const medusaPublishableApiKey = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY!;
|
||||
const medusaPublishableApiKey =
|
||||
process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY!;
|
||||
const key = process.env.MEDUSA_SECRET_API_KEY!;
|
||||
|
||||
if (!medusaBackendUrl || !medusaPublishableApiKey) {
|
||||
@@ -13,4 +14,4 @@ export const getAdminSdk = () => {
|
||||
debug: process.env.NODE_ENV === 'development',
|
||||
apiKey: key,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,7 +4,5 @@
|
||||
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
|
||||
},
|
||||
"include": ["*.ts", "src"],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export function AuthLayoutShell({
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
'sm:py-auto flex flex-col items-center justify-center py-6 h-screen' +
|
||||
'sm:py-auto flex h-screen flex-col items-center justify-center py-6' +
|
||||
' bg-background lg:bg-muted/30 gap-y-10 lg:gap-y-8'
|
||||
}
|
||||
>
|
||||
|
||||
@@ -4,13 +4,13 @@ import { CheckCircledIcon } from '@radix-ui/react-icons';
|
||||
|
||||
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
||||
import { If } from '@kit/ui/if';
|
||||
import { Spinner } from '@kit/ui/makerkit/spinner';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { useCaptchaToken } from '../captcha/client';
|
||||
import { usePasswordSignUpFlow } from '../hooks/use-sign-up-flow';
|
||||
import { AuthErrorAlert } from './auth-error-alert';
|
||||
import { PasswordSignUpForm } from './password-sign-up-form';
|
||||
import { Spinner } from '@kit/ui/makerkit/spinner';
|
||||
|
||||
interface EmailPasswordSignUpContainerProps {
|
||||
authConfig: {
|
||||
@@ -56,8 +56,9 @@ export function EmailPasswordSignUpContainer({
|
||||
<div className="flex justify-center">
|
||||
<Spinner />
|
||||
</div>
|
||||
) : <SuccessAlert />
|
||||
}
|
||||
) : (
|
||||
<SuccessAlert />
|
||||
)}
|
||||
</If>
|
||||
|
||||
<If condition={!showVerifyEmailAlert}>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import type { Provider } from '@supabase/supabase-js';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import type { Provider } from '@supabase/supabase-js';
|
||||
|
||||
import { isBrowser } from '@kit/shared/utils';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
||||
import { If } from '@kit/ui/if';
|
||||
@@ -53,7 +54,7 @@ export function SignUpMethodsContainer(props: {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
router.replace(props.paths.updateAccount)
|
||||
router.replace(props.paths.updateAccount);
|
||||
}, 2_500);
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -43,4 +43,4 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
'use server';
|
||||
|
||||
import { getLogger } from '@kit/shared/logger';
|
||||
|
||||
import {
|
||||
getOpenResponses,
|
||||
getOtherResponses,
|
||||
getUserDoneResponses,
|
||||
getUserInProgressResponses,
|
||||
} from '@kit/doctor/services/doctor-analysis.service';
|
||||
import { getLogger } from '@kit/shared/logger';
|
||||
|
||||
import { doctorAction } from '../utils/doctor-action';
|
||||
|
||||
export const getUserDoneResponsesAction = doctorAction(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import z from 'zod';
|
||||
|
||||
import { Database } from '@kit/supabase/database';
|
||||
import z from 'zod';
|
||||
|
||||
export const doctorJobSelectSchema = z.object({
|
||||
userId: z.uuid(),
|
||||
|
||||
@@ -9,9 +9,7 @@ import { Database } from '@kit/supabase/database';
|
||||
*/
|
||||
export async function isDoctor(client: SupabaseClient<Database>) {
|
||||
try {
|
||||
const { data, error } = await client
|
||||
.schema('medreport')
|
||||
.rpc('is_doctor');
|
||||
const { data, error } = await client.schema('medreport').rpc('is_doctor');
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
|
||||
@@ -9,17 +9,9 @@
|
||||
"./services/*": "./src/lib/server/services/*.ts",
|
||||
"./actions/*": "./src/lib/server/actions/*.ts"
|
||||
},
|
||||
"include": [
|
||||
"*.ts",
|
||||
"src",
|
||||
"app"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
"include": ["*.ts", "src", "app"],
|
||||
"exclude": ["node_modules"],
|
||||
"paths": {
|
||||
"@components/*": [
|
||||
"./src/lib/*"
|
||||
],
|
||||
"@components/*": ["./src/lib/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
const c = require("ansi-colors")
|
||||
const c = require('ansi-colors');
|
||||
|
||||
const requiredEnvs = [
|
||||
{
|
||||
key: "NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY",
|
||||
key: 'NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY',
|
||||
// TODO: we need a good doc to point this to
|
||||
description:
|
||||
"Learn how to create a publishable key: https://docs.medusajs.com/v2/resources/storefront-development/publishable-api-keys",
|
||||
'Learn how to create a publishable key: https://docs.medusajs.com/v2/resources/storefront-development/publishable-api-keys',
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
function checkEnvVariables() {
|
||||
const missingEnvs = requiredEnvs.filter(function (env) {
|
||||
return !process.env[env.key]
|
||||
})
|
||||
return !process.env[env.key];
|
||||
});
|
||||
|
||||
if (missingEnvs.length > 0) {
|
||||
console.error(
|
||||
c.red.bold("\n🚫 Error: Missing required environment variables\n")
|
||||
)
|
||||
c.red.bold('\n🚫 Error: Missing required environment variables\n'),
|
||||
);
|
||||
|
||||
missingEnvs.forEach(function (env) {
|
||||
console.error(c.yellow(` ${c.bold(env.key)}`))
|
||||
console.error(c.yellow(` ${c.bold(env.key)}`));
|
||||
if (env.description) {
|
||||
console.error(c.dim(` ${env.description}\n`))
|
||||
console.error(c.dim(` ${env.description}\n`));
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
console.error(
|
||||
c.yellow(
|
||||
"\nPlease set these variables in your .env file or environment before starting the application.\n"
|
||||
)
|
||||
)
|
||||
'\nPlease set these variables in your .env file or environment before starting the application.\n',
|
||||
),
|
||||
);
|
||||
|
||||
process.exit(1)
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = checkEnvVariables
|
||||
module.exports = checkEnvVariables;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Medusa from "@medusajs/js-sdk";
|
||||
import Medusa from '@medusajs/js-sdk';
|
||||
|
||||
// Defaults to standard port for Medusa server
|
||||
let MEDUSA_BACKEND_URL = "http://localhost:9000";
|
||||
let MEDUSA_BACKEND_URL = 'http://localhost:9000';
|
||||
|
||||
if (process.env.MEDUSA_BACKEND_URL) {
|
||||
MEDUSA_BACKEND_URL = process.env.MEDUSA_BACKEND_URL;
|
||||
@@ -9,7 +9,7 @@ if (process.env.MEDUSA_BACKEND_URL) {
|
||||
|
||||
export const SDK_CONFIG = {
|
||||
baseUrl: MEDUSA_BACKEND_URL,
|
||||
debug: process.env.NODE_ENV === "development",
|
||||
debug: process.env.NODE_ENV === 'development',
|
||||
publishableKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from "react"
|
||||
import { CreditCard } from "@medusajs/icons"
|
||||
import React from 'react';
|
||||
|
||||
import Ideal from "@modules/common/icons/ideal"
|
||||
import Bancontact from "@modules/common/icons/bancontact"
|
||||
import PayPal from "@modules/common/icons/paypal"
|
||||
import { CreditCard } from '@medusajs/icons';
|
||||
import Bancontact from '@modules/common/icons/bancontact';
|
||||
import Ideal from '@modules/common/icons/ideal';
|
||||
import PayPal from '@modules/common/icons/paypal';
|
||||
|
||||
/* Map of payment provider_id to their title and icon. Add in any payment providers you want to use. */
|
||||
export const paymentInfoMap: Record<
|
||||
@@ -11,58 +11,58 @@ export const paymentInfoMap: Record<
|
||||
{ title: string; icon: React.JSX.Element }
|
||||
> = {
|
||||
pp_stripe_stripe: {
|
||||
title: "Credit card",
|
||||
title: 'Credit card',
|
||||
icon: <CreditCard />,
|
||||
},
|
||||
"pp_stripe-ideal_stripe": {
|
||||
title: "iDeal",
|
||||
'pp_stripe-ideal_stripe': {
|
||||
title: 'iDeal',
|
||||
icon: <Ideal />,
|
||||
},
|
||||
"pp_stripe-bancontact_stripe": {
|
||||
title: "Bancontact",
|
||||
'pp_stripe-bancontact_stripe': {
|
||||
title: 'Bancontact',
|
||||
icon: <Bancontact />,
|
||||
},
|
||||
pp_paypal_paypal: {
|
||||
title: "PayPal",
|
||||
title: 'PayPal',
|
||||
icon: <PayPal />,
|
||||
},
|
||||
pp_system_default: {
|
||||
title: "Manual Payment",
|
||||
title: 'Manual Payment',
|
||||
icon: <CreditCard />,
|
||||
},
|
||||
// Add more payment providers here
|
||||
}
|
||||
};
|
||||
|
||||
// This only checks if it is native stripe for card payments, it ignores the other stripe-based providers
|
||||
export const isStripe = (providerId?: string) => {
|
||||
return providerId?.startsWith("pp_stripe_")
|
||||
}
|
||||
return providerId?.startsWith('pp_stripe_');
|
||||
};
|
||||
export const isPaypal = (providerId?: string) => {
|
||||
return providerId?.startsWith("pp_paypal")
|
||||
}
|
||||
return providerId?.startsWith('pp_paypal');
|
||||
};
|
||||
export const isManual = (providerId?: string) => {
|
||||
return providerId?.startsWith("pp_system_default")
|
||||
}
|
||||
return providerId?.startsWith('pp_system_default');
|
||||
};
|
||||
|
||||
// Add currencies that don't need to be divided by 100
|
||||
export const noDivisionCurrencies = [
|
||||
"krw",
|
||||
"jpy",
|
||||
"vnd",
|
||||
"clp",
|
||||
"pyg",
|
||||
"xaf",
|
||||
"xof",
|
||||
"bif",
|
||||
"djf",
|
||||
"gnf",
|
||||
"kmf",
|
||||
"mga",
|
||||
"rwf",
|
||||
"xpf",
|
||||
"htg",
|
||||
"vuv",
|
||||
"xag",
|
||||
"xdr",
|
||||
"xau",
|
||||
]
|
||||
'krw',
|
||||
'jpy',
|
||||
'vnd',
|
||||
'clp',
|
||||
'pyg',
|
||||
'xaf',
|
||||
'xof',
|
||||
'bif',
|
||||
'djf',
|
||||
'gnf',
|
||||
'kmf',
|
||||
'mga',
|
||||
'rwf',
|
||||
'xpf',
|
||||
'htg',
|
||||
'vuv',
|
||||
'xag',
|
||||
'xdr',
|
||||
'xau',
|
||||
];
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
"use client"
|
||||
'use client';
|
||||
|
||||
import React, { createContext, useContext } from "react"
|
||||
import React, { createContext, useContext } from 'react';
|
||||
|
||||
interface ModalContext {
|
||||
close: () => void
|
||||
close: () => void;
|
||||
}
|
||||
|
||||
const ModalContext = createContext<ModalContext | null>(null)
|
||||
const ModalContext = createContext<ModalContext | null>(null);
|
||||
|
||||
interface ModalProviderProps {
|
||||
children?: React.ReactNode
|
||||
close: () => void
|
||||
children?: React.ReactNode;
|
||||
close: () => void;
|
||||
}
|
||||
|
||||
export const ModalProvider = ({ children, close }: ModalProviderProps) => {
|
||||
@@ -22,13 +22,13 @@ export const ModalProvider = ({ children, close }: ModalProviderProps) => {
|
||||
>
|
||||
{children}
|
||||
</ModalContext.Provider>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const useModal = () => {
|
||||
const context = useContext(ModalContext)
|
||||
const context = useContext(ModalContext);
|
||||
if (context === null) {
|
||||
throw new Error("useModal must be used within a ModalProvider")
|
||||
throw new Error('useModal must be used within a ModalProvider');
|
||||
}
|
||||
return context
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
"use server";
|
||||
'use server';
|
||||
|
||||
import { revalidateTag } from 'next/cache';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
import { sdk } from '@lib/config';
|
||||
import medusaError from '@lib/util/medusa-error';
|
||||
import { HttpTypes } from '@medusajs/types';
|
||||
|
||||
import medusaError from "@lib/util/medusa-error";
|
||||
import { HttpTypes } from "@medusajs/types";
|
||||
import { revalidateTag } from "next/cache";
|
||||
import { redirect } from "next/navigation";
|
||||
import {
|
||||
getAuthHeaders,
|
||||
getCacheOptions,
|
||||
@@ -11,10 +14,9 @@ import {
|
||||
getCartId,
|
||||
removeCartId,
|
||||
setCartId,
|
||||
} from "./cookies";
|
||||
import { getRegion } from "./regions";
|
||||
import { sdk } from "@lib/config";
|
||||
import { retrieveOrder } from "./orders";
|
||||
} from './cookies';
|
||||
import { retrieveOrder } from './orders';
|
||||
import { getRegion } from './regions';
|
||||
|
||||
/**
|
||||
* Retrieves a cart by its ID. If no ID is provided, it will use the cart ID from the cookies.
|
||||
@@ -33,15 +35,15 @@ export async function retrieveCart(cartId?: string) {
|
||||
};
|
||||
|
||||
const next = {
|
||||
...(await getCacheOptions("carts")),
|
||||
...(await getCacheOptions('carts')),
|
||||
};
|
||||
|
||||
return await sdk.client
|
||||
.fetch<HttpTypes.StoreCartResponse>(`/store/carts/${id}`, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
query: {
|
||||
fields:
|
||||
"*items, *region, *items.product, *items.variant, *items.thumbnail, *items.metadata, +items.total, *promotions, +shipping_methods.name",
|
||||
'*items, *region, *items.product, *items.variant, *items.thumbnail, *items.metadata, +items.total, *promotions, +shipping_methods.name',
|
||||
},
|
||||
headers,
|
||||
next,
|
||||
@@ -68,19 +70,19 @@ export async function getOrSetCart(countryCode: string) {
|
||||
const cartResp = await sdk.store.cart.create(
|
||||
{ region_id: region.id },
|
||||
{},
|
||||
headers
|
||||
headers,
|
||||
);
|
||||
cart = cartResp.cart;
|
||||
|
||||
await setCartId(cart.id);
|
||||
|
||||
const cartCacheTag = await getCacheTag("carts");
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
}
|
||||
|
||||
if (cart && cart?.region_id !== region.id) {
|
||||
await sdk.store.cart.update(cart.id, { region_id: region.id }, {}, headers);
|
||||
const cartCacheTag = await getCacheTag("carts");
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
}
|
||||
|
||||
@@ -89,13 +91,16 @@ export async function getOrSetCart(countryCode: string) {
|
||||
|
||||
export async function updateCart(
|
||||
{ id, ...data }: HttpTypes.StoreUpdateCart & { id?: string },
|
||||
{ onSuccess, onError }: { onSuccess: () => void, onError: () => void } = { onSuccess: () => {}, onError: () => {} },
|
||||
{ onSuccess, onError }: { onSuccess: () => void; onError: () => void } = {
|
||||
onSuccess: () => {},
|
||||
onError: () => {},
|
||||
},
|
||||
) {
|
||||
const cartId = id || (await getCartId());
|
||||
|
||||
if (!cartId) {
|
||||
throw new Error(
|
||||
"No existing cart found, please create one before updating"
|
||||
'No existing cart found, please create one before updating',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -106,10 +111,10 @@ export async function updateCart(
|
||||
return sdk.store.cart
|
||||
.update(cartId, data, {}, headers)
|
||||
.then(async ({ cart }) => {
|
||||
const cartCacheTag = await getCacheTag("carts");
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
|
||||
const fulfillmentCacheTag = await getCacheTag("fulfillment");
|
||||
const fulfillmentCacheTag = await getCacheTag('fulfillment');
|
||||
revalidateTag(fulfillmentCacheTag);
|
||||
|
||||
onSuccess();
|
||||
@@ -131,13 +136,13 @@ export async function addToCart({
|
||||
countryCode: string;
|
||||
}) {
|
||||
if (!variantId) {
|
||||
throw new Error("Missing variant ID when adding to cart");
|
||||
throw new Error('Missing variant ID when adding to cart');
|
||||
}
|
||||
|
||||
const cart = await getOrSetCart(countryCode);
|
||||
|
||||
if (!cart) {
|
||||
throw new Error("Error retrieving or creating cart");
|
||||
throw new Error('Error retrieving or creating cart');
|
||||
}
|
||||
|
||||
const headers = {
|
||||
@@ -152,13 +157,13 @@ export async function addToCart({
|
||||
quantity,
|
||||
},
|
||||
{},
|
||||
headers
|
||||
headers,
|
||||
)
|
||||
.then(async () => {
|
||||
const cartCacheTag = await getCacheTag("carts");
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
|
||||
const fulfillmentCacheTag = await getCacheTag("fulfillment");
|
||||
const fulfillmentCacheTag = await getCacheTag('fulfillment');
|
||||
revalidateTag(fulfillmentCacheTag);
|
||||
})
|
||||
.catch(medusaError);
|
||||
@@ -176,13 +181,13 @@ export async function updateLineItem({
|
||||
metadata?: Record<string, any>;
|
||||
}) {
|
||||
if (!lineId) {
|
||||
throw new Error("Missing lineItem ID when updating line item");
|
||||
throw new Error('Missing lineItem ID when updating line item');
|
||||
}
|
||||
|
||||
const cartId = await getCartId();
|
||||
|
||||
if (!cartId) {
|
||||
throw new Error("Missing cart ID when updating line item");
|
||||
throw new Error('Missing cart ID when updating line item');
|
||||
}
|
||||
|
||||
const headers = {
|
||||
@@ -192,10 +197,10 @@ export async function updateLineItem({
|
||||
await sdk.store.cart
|
||||
.updateLineItem(cartId, lineId, { quantity, metadata }, {}, headers)
|
||||
.then(async () => {
|
||||
const cartCacheTag = await getCacheTag("carts");
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
|
||||
const fulfillmentCacheTag = await getCacheTag("fulfillment");
|
||||
const fulfillmentCacheTag = await getCacheTag('fulfillment');
|
||||
revalidateTag(fulfillmentCacheTag);
|
||||
})
|
||||
.catch(medusaError);
|
||||
@@ -203,13 +208,13 @@ export async function updateLineItem({
|
||||
|
||||
export async function deleteLineItem(lineId: string) {
|
||||
if (!lineId) {
|
||||
throw new Error("Missing lineItem ID when deleting line item");
|
||||
throw new Error('Missing lineItem ID when deleting line item');
|
||||
}
|
||||
|
||||
const cartId = await getCartId();
|
||||
|
||||
if (!cartId) {
|
||||
throw new Error("Missing cart ID when deleting line item");
|
||||
throw new Error('Missing cart ID when deleting line item');
|
||||
}
|
||||
|
||||
const headers = {
|
||||
@@ -219,10 +224,10 @@ export async function deleteLineItem(lineId: string) {
|
||||
await sdk.store.cart
|
||||
.deleteLineItem(cartId, lineId, headers)
|
||||
.then(async () => {
|
||||
const cartCacheTag = await getCacheTag("carts");
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
|
||||
const fulfillmentCacheTag = await getCacheTag("fulfillment");
|
||||
const fulfillmentCacheTag = await getCacheTag('fulfillment');
|
||||
revalidateTag(fulfillmentCacheTag);
|
||||
})
|
||||
.catch(medusaError);
|
||||
@@ -242,7 +247,7 @@ export async function setShippingMethod({
|
||||
return sdk.store.cart
|
||||
.addShippingMethod(cartId, { option_id: shippingMethodId }, {}, headers)
|
||||
.then(async () => {
|
||||
const cartCacheTag = await getCacheTag("carts");
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
})
|
||||
.catch(medusaError);
|
||||
@@ -250,7 +255,7 @@ export async function setShippingMethod({
|
||||
|
||||
export async function initiatePaymentSession(
|
||||
cart: HttpTypes.StoreCart,
|
||||
data: HttpTypes.StoreInitializePaymentSession
|
||||
data: HttpTypes.StoreInitializePaymentSession,
|
||||
) {
|
||||
const headers = {
|
||||
...(await getAuthHeaders()),
|
||||
@@ -259,7 +264,7 @@ export async function initiatePaymentSession(
|
||||
return sdk.store.payment
|
||||
.initiatePaymentSession(cart, data, {}, headers)
|
||||
.then(async (resp) => {
|
||||
const cartCacheTag = await getCacheTag("carts");
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
return resp;
|
||||
})
|
||||
@@ -268,12 +273,15 @@ export async function initiatePaymentSession(
|
||||
|
||||
export async function applyPromotions(
|
||||
codes: string[],
|
||||
{ onSuccess, onError }: { onSuccess: () => void, onError: () => void } = { onSuccess: () => {}, onError: () => {} },
|
||||
{ onSuccess, onError }: { onSuccess: () => void; onError: () => void } = {
|
||||
onSuccess: () => {},
|
||||
onError: () => {},
|
||||
},
|
||||
) {
|
||||
const cartId = await getCartId();
|
||||
|
||||
if (!cartId) {
|
||||
throw new Error("No existing cart found");
|
||||
throw new Error('No existing cart found');
|
||||
}
|
||||
|
||||
const headers = {
|
||||
@@ -283,10 +291,10 @@ export async function applyPromotions(
|
||||
return sdk.store.cart
|
||||
.update(cartId, { promo_codes: codes }, {}, headers)
|
||||
.then(async () => {
|
||||
const cartCacheTag = await getCacheTag("carts");
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
|
||||
const fulfillmentCacheTag = await getCacheTag("fulfillment");
|
||||
const fulfillmentCacheTag = await getCacheTag('fulfillment');
|
||||
revalidateTag(fulfillmentCacheTag);
|
||||
|
||||
onSuccess();
|
||||
@@ -322,7 +330,7 @@ export async function removeDiscount(code: string) {
|
||||
|
||||
export async function removeGiftCard(
|
||||
codeToRemove: string,
|
||||
giftCards: any[]
|
||||
giftCards: any[],
|
||||
// giftCards: GiftCard[]
|
||||
) {
|
||||
// const cartId = getCartId()
|
||||
@@ -342,9 +350,9 @@ export async function removeGiftCard(
|
||||
|
||||
export async function submitPromotionForm(
|
||||
currentState: unknown,
|
||||
formData: FormData
|
||||
formData: FormData,
|
||||
) {
|
||||
const code = formData.get("code") as string;
|
||||
const code = formData.get('code') as string;
|
||||
try {
|
||||
await applyPromotions([code]);
|
||||
} catch (e: any) {
|
||||
@@ -356,44 +364,44 @@ export async function submitPromotionForm(
|
||||
export async function setAddresses(currentState: unknown, formData: FormData) {
|
||||
try {
|
||||
if (!formData) {
|
||||
throw new Error("No form data found when setting addresses");
|
||||
throw new Error('No form data found when setting addresses');
|
||||
}
|
||||
const cartId = getCartId();
|
||||
if (!cartId) {
|
||||
throw new Error("No existing cart found when setting addresses");
|
||||
throw new Error('No existing cart found when setting addresses');
|
||||
}
|
||||
|
||||
const data = {
|
||||
shipping_address: {
|
||||
first_name: formData.get("shipping_address.first_name"),
|
||||
last_name: formData.get("shipping_address.last_name"),
|
||||
address_1: formData.get("shipping_address.address_1"),
|
||||
address_2: "",
|
||||
company: formData.get("shipping_address.company"),
|
||||
postal_code: formData.get("shipping_address.postal_code"),
|
||||
city: formData.get("shipping_address.city"),
|
||||
country_code: formData.get("shipping_address.country_code"),
|
||||
province: formData.get("shipping_address.province"),
|
||||
phone: formData.get("shipping_address.phone"),
|
||||
first_name: formData.get('shipping_address.first_name'),
|
||||
last_name: formData.get('shipping_address.last_name'),
|
||||
address_1: formData.get('shipping_address.address_1'),
|
||||
address_2: '',
|
||||
company: formData.get('shipping_address.company'),
|
||||
postal_code: formData.get('shipping_address.postal_code'),
|
||||
city: formData.get('shipping_address.city'),
|
||||
country_code: formData.get('shipping_address.country_code'),
|
||||
province: formData.get('shipping_address.province'),
|
||||
phone: formData.get('shipping_address.phone'),
|
||||
},
|
||||
email: formData.get("email"),
|
||||
email: formData.get('email'),
|
||||
} as any;
|
||||
|
||||
const sameAsBilling = formData.get("same_as_billing");
|
||||
if (sameAsBilling === "on") data.billing_address = data.shipping_address;
|
||||
const sameAsBilling = formData.get('same_as_billing');
|
||||
if (sameAsBilling === 'on') data.billing_address = data.shipping_address;
|
||||
|
||||
if (sameAsBilling !== "on")
|
||||
if (sameAsBilling !== 'on')
|
||||
data.billing_address = {
|
||||
first_name: formData.get("billing_address.first_name"),
|
||||
last_name: formData.get("billing_address.last_name"),
|
||||
address_1: formData.get("billing_address.address_1"),
|
||||
address_2: "",
|
||||
company: formData.get("billing_address.company"),
|
||||
postal_code: formData.get("billing_address.postal_code"),
|
||||
city: formData.get("billing_address.city"),
|
||||
country_code: formData.get("billing_address.country_code"),
|
||||
province: formData.get("billing_address.province"),
|
||||
phone: formData.get("billing_address.phone"),
|
||||
first_name: formData.get('billing_address.first_name'),
|
||||
last_name: formData.get('billing_address.last_name'),
|
||||
address_1: formData.get('billing_address.address_1'),
|
||||
address_2: '',
|
||||
company: formData.get('billing_address.company'),
|
||||
postal_code: formData.get('billing_address.postal_code'),
|
||||
city: formData.get('billing_address.city'),
|
||||
country_code: formData.get('billing_address.country_code'),
|
||||
province: formData.get('billing_address.province'),
|
||||
phone: formData.get('billing_address.phone'),
|
||||
};
|
||||
await updateCart(data);
|
||||
} catch (e: any) {
|
||||
@@ -401,7 +409,7 @@ export async function setAddresses(currentState: unknown, formData: FormData) {
|
||||
}
|
||||
|
||||
redirect(
|
||||
`/${formData.get("shipping_address.country_code")}/checkout?step=delivery`
|
||||
`/${formData.get('shipping_address.country_code')}/checkout?step=delivery`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -410,11 +418,14 @@ export async function setAddresses(currentState: unknown, formData: FormData) {
|
||||
* @param cartId - optional - The ID of the cart to place an order for.
|
||||
* @returns The cart object if the order was successful, or null if not.
|
||||
*/
|
||||
export async function placeOrder(cartId?: string, options: { revalidateCacheTags: boolean } = { revalidateCacheTags: true }) {
|
||||
export async function placeOrder(
|
||||
cartId?: string,
|
||||
options: { revalidateCacheTags: boolean } = { revalidateCacheTags: true },
|
||||
) {
|
||||
const id = cartId || (await getCartId());
|
||||
|
||||
if (!id) {
|
||||
throw new Error("No existing cart found when placing an order");
|
||||
throw new Error('No existing cart found when placing an order');
|
||||
}
|
||||
|
||||
const headers = {
|
||||
@@ -425,22 +436,22 @@ export async function placeOrder(cartId?: string, options: { revalidateCacheTags
|
||||
.complete(id, {}, headers)
|
||||
.then(async (cartRes) => {
|
||||
if (options?.revalidateCacheTags) {
|
||||
const cartCacheTag = await getCacheTag("carts");
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
}
|
||||
return cartRes;
|
||||
})
|
||||
.catch(medusaError);
|
||||
|
||||
if (cartRes?.type === "order") {
|
||||
if (cartRes?.type === 'order') {
|
||||
if (options?.revalidateCacheTags) {
|
||||
const orderCacheTag = await getCacheTag("orders");
|
||||
const orderCacheTag = await getCacheTag('orders');
|
||||
revalidateTag(orderCacheTag);
|
||||
}
|
||||
|
||||
removeCartId();
|
||||
} else {
|
||||
throw new Error("Cart is not an order");
|
||||
throw new Error('Cart is not an order');
|
||||
}
|
||||
|
||||
return retrieveOrder(cartRes.order.id);
|
||||
@@ -461,14 +472,14 @@ export async function updateRegion(countryCode: string, currentPath: string) {
|
||||
|
||||
if (cartId) {
|
||||
await updateCart({ region_id: region.id });
|
||||
const cartCacheTag = await getCacheTag("carts");
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
}
|
||||
|
||||
const regionCacheTag = await getCacheTag("regions");
|
||||
const regionCacheTag = await getCacheTag('regions');
|
||||
revalidateTag(regionCacheTag);
|
||||
|
||||
const productsCacheTag = await getCacheTag("products");
|
||||
const productsCacheTag = await getCacheTag('products');
|
||||
revalidateTag(productsCacheTag);
|
||||
|
||||
redirect(`/${countryCode}${currentPath}`);
|
||||
@@ -480,15 +491,15 @@ export async function listCartOptions() {
|
||||
...(await getAuthHeaders()),
|
||||
};
|
||||
const next = {
|
||||
...(await getCacheOptions("shippingOptions")),
|
||||
...(await getCacheOptions('shippingOptions')),
|
||||
};
|
||||
|
||||
return await sdk.client.fetch<{
|
||||
shipping_options: HttpTypes.StoreCartShippingOption[];
|
||||
}>("/store/shipping-options", {
|
||||
}>('/store/shipping-options', {
|
||||
query: { cart_id: cartId },
|
||||
next,
|
||||
headers,
|
||||
cache: "force-cache",
|
||||
cache: 'force-cache',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,34 +1,35 @@
|
||||
import { sdk } from "@lib/config";
|
||||
import { HttpTypes } from "@medusajs/types";
|
||||
import { getCacheOptions } from "./cookies";
|
||||
import { sdk } from '@lib/config';
|
||||
import { HttpTypes } from '@medusajs/types';
|
||||
|
||||
import { getCacheOptions } from './cookies';
|
||||
|
||||
export const listCategories = async (query?: Record<string, any>) => {
|
||||
const next = {
|
||||
...(await getCacheOptions("categories")),
|
||||
...(await getCacheOptions('categories')),
|
||||
};
|
||||
|
||||
const limit = query?.limit || 100;
|
||||
|
||||
return sdk.client
|
||||
.fetch<{ product_categories: HttpTypes.StoreProductCategory[] }>(
|
||||
"/store/product-categories",
|
||||
'/store/product-categories',
|
||||
{
|
||||
query: {
|
||||
fields:
|
||||
"*category_children, *products, *parent_category, *parent_category.parent_category",
|
||||
'*category_children, *products, *parent_category, *parent_category.parent_category',
|
||||
limit,
|
||||
...query,
|
||||
},
|
||||
next,
|
||||
cache: "force-cache",
|
||||
}
|
||||
cache: 'force-cache',
|
||||
},
|
||||
)
|
||||
.then(({ product_categories }) => product_categories);
|
||||
};
|
||||
|
||||
export const getCategoryByHandle = async (categoryHandle: string[]) => {
|
||||
const { product_categories } = await getProductCategories({
|
||||
handle: `${categoryHandle.join("/")}`,
|
||||
handle: `${categoryHandle.join('/')}`,
|
||||
limit: 1,
|
||||
});
|
||||
return product_categories[0];
|
||||
@@ -37,14 +38,14 @@ export const getCategoryByHandle = async (categoryHandle: string[]) => {
|
||||
export const getProductCategories = async ({
|
||||
handle,
|
||||
limit,
|
||||
fields = "*category_children, *products",
|
||||
fields = '*category_children, *products',
|
||||
}: {
|
||||
handle?: string;
|
||||
limit?: number;
|
||||
fields?: string;
|
||||
} = {}) => {
|
||||
const next = {
|
||||
...(await getCacheOptions("categories")),
|
||||
...(await getCacheOptions('categories')),
|
||||
};
|
||||
|
||||
return sdk.client.fetch<HttpTypes.StoreProductCategoryListResponse>(
|
||||
@@ -57,6 +58,6 @@ export const getProductCategories = async ({
|
||||
},
|
||||
next,
|
||||
//cache: "force-cache",
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
"use server";
|
||||
'use server';
|
||||
|
||||
import { sdk, SDK_CONFIG } from "@lib/config";
|
||||
import { HttpTypes } from "@medusajs/types";
|
||||
import { getCacheOptions } from "./cookies";
|
||||
import { SDK_CONFIG, sdk } from '@lib/config';
|
||||
import { HttpTypes } from '@medusajs/types';
|
||||
|
||||
import { getCacheOptions } from './cookies';
|
||||
|
||||
export const retrieveCollection = async (id: string) => {
|
||||
const next = {
|
||||
...(await getCacheOptions("collections")),
|
||||
...(await getCacheOptions('collections')),
|
||||
};
|
||||
|
||||
return sdk.client
|
||||
@@ -14,46 +15,46 @@ export const retrieveCollection = async (id: string) => {
|
||||
`/store/collections/${id}`,
|
||||
{
|
||||
next,
|
||||
cache: "force-cache",
|
||||
}
|
||||
cache: 'force-cache',
|
||||
},
|
||||
)
|
||||
.then(({ collection }) => collection);
|
||||
};
|
||||
|
||||
export const listCollections = async (
|
||||
queryParams: Record<string, string> = {}
|
||||
queryParams: Record<string, string> = {},
|
||||
): Promise<{ collections: HttpTypes.StoreCollection[]; count: number }> => {
|
||||
const next = {
|
||||
...(await getCacheOptions("collections")),
|
||||
...(await getCacheOptions('collections')),
|
||||
};
|
||||
|
||||
queryParams.limit = queryParams.limit || "100";
|
||||
queryParams.offset = queryParams.offset || "0";
|
||||
console.log("SDK_CONFIG: ", SDK_CONFIG.baseUrl);
|
||||
queryParams.limit = queryParams.limit || '100';
|
||||
queryParams.offset = queryParams.offset || '0';
|
||||
console.log('SDK_CONFIG: ', SDK_CONFIG.baseUrl);
|
||||
return sdk.client
|
||||
.fetch<{ collections: HttpTypes.StoreCollection[]; count: number }>(
|
||||
"/store/collections",
|
||||
'/store/collections',
|
||||
{
|
||||
query: queryParams,
|
||||
next,
|
||||
cache: "force-cache",
|
||||
}
|
||||
cache: 'force-cache',
|
||||
},
|
||||
)
|
||||
.then(({ collections }) => ({ collections, count: collections.length }));
|
||||
};
|
||||
|
||||
export const getCollectionByHandle = async (
|
||||
handle: string
|
||||
handle: string,
|
||||
): Promise<HttpTypes.StoreCollection> => {
|
||||
const next = {
|
||||
...(await getCacheOptions("collections")),
|
||||
...(await getCacheOptions('collections')),
|
||||
};
|
||||
|
||||
return sdk.client
|
||||
.fetch<HttpTypes.StoreCollectionListResponse>(`/store/collections`, {
|
||||
query: { handle, fields: "*products" },
|
||||
query: { handle, fields: '*products' },
|
||||
next,
|
||||
cache: "force-cache",
|
||||
cache: 'force-cache',
|
||||
})
|
||||
.then(({ collections }) => collections[0]);
|
||||
};
|
||||
|
||||
@@ -1,124 +1,124 @@
|
||||
import "server-only"
|
||||
import 'server-only';
|
||||
|
||||
import { cookies as nextCookies } from "next/headers"
|
||||
import { cookies as nextCookies } from 'next/headers';
|
||||
|
||||
const CookieName = {
|
||||
MEDUSA_CUSTOMER_ID: "_medusa_customer_id",
|
||||
MEDUSA_JWT: "_medusa_jwt",
|
||||
MEDUSA_CART_ID: "_medusa_cart_id",
|
||||
MEDUSA_CACHE_ID: "_medusa_cache_id",
|
||||
}
|
||||
MEDUSA_CUSTOMER_ID: '_medusa_customer_id',
|
||||
MEDUSA_JWT: '_medusa_jwt',
|
||||
MEDUSA_CART_ID: '_medusa_cart_id',
|
||||
MEDUSA_CACHE_ID: '_medusa_cache_id',
|
||||
};
|
||||
|
||||
export const getAuthHeaders = async (): Promise<
|
||||
{ authorization: string } | {}
|
||||
> => {
|
||||
try {
|
||||
const cookies = await nextCookies()
|
||||
const token = cookies.get(CookieName.MEDUSA_JWT)?.value
|
||||
const cookies = await nextCookies();
|
||||
const token = cookies.get(CookieName.MEDUSA_JWT)?.value;
|
||||
|
||||
if (!token) {
|
||||
return {}
|
||||
return {};
|
||||
}
|
||||
|
||||
return { authorization: `Bearer ${token}` }
|
||||
return { authorization: `Bearer ${token}` };
|
||||
} catch {
|
||||
return {}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getMedusaCustomerId = async (): Promise<
|
||||
{ customerId: string | null }
|
||||
> => {
|
||||
export const getMedusaCustomerId = async (): Promise<{
|
||||
customerId: string | null;
|
||||
}> => {
|
||||
try {
|
||||
const cookies = await nextCookies()
|
||||
const customerId = cookies.get(CookieName.MEDUSA_CUSTOMER_ID)?.value
|
||||
const cookies = await nextCookies();
|
||||
const customerId = cookies.get(CookieName.MEDUSA_CUSTOMER_ID)?.value;
|
||||
|
||||
if (!customerId) {
|
||||
return { customerId: null }
|
||||
return { customerId: null };
|
||||
}
|
||||
|
||||
return { customerId }
|
||||
return { customerId };
|
||||
} catch {
|
||||
return { customerId: null }
|
||||
return { customerId: null };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getCacheTag = async (tag: string): Promise<string> => {
|
||||
try {
|
||||
const cookies = await nextCookies()
|
||||
const cacheId = cookies.get(CookieName.MEDUSA_CACHE_ID)?.value
|
||||
const cookies = await nextCookies();
|
||||
const cacheId = cookies.get(CookieName.MEDUSA_CACHE_ID)?.value;
|
||||
|
||||
if (!cacheId) {
|
||||
return ""
|
||||
return '';
|
||||
}
|
||||
|
||||
return `${tag}-${cacheId}`
|
||||
return `${tag}-${cacheId}`;
|
||||
} catch (error) {
|
||||
return ""
|
||||
return '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getCacheOptions = async (
|
||||
tag: string
|
||||
tag: string,
|
||||
): Promise<{ tags: string[] } | {}> => {
|
||||
if (typeof window !== "undefined") {
|
||||
return {}
|
||||
if (typeof window !== 'undefined') {
|
||||
return {};
|
||||
}
|
||||
|
||||
const cacheTag = await getCacheTag(tag)
|
||||
const cacheTag = await getCacheTag(tag);
|
||||
|
||||
if (!cacheTag) {
|
||||
return {}
|
||||
return {};
|
||||
}
|
||||
|
||||
return { tags: [`${cacheTag}`] }
|
||||
}
|
||||
return { tags: [`${cacheTag}`] };
|
||||
};
|
||||
|
||||
const getCookieSharedOptions = () => ({
|
||||
maxAge: 60 * 60 * 24 * 7,
|
||||
httpOnly: false,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
});
|
||||
const getCookieResetOptions = () => ({
|
||||
maxAge: -1,
|
||||
});
|
||||
|
||||
export const setAuthToken = async (token: string) => {
|
||||
const cookies = await nextCookies()
|
||||
const cookies = await nextCookies();
|
||||
cookies.set(CookieName.MEDUSA_JWT, token, {
|
||||
...getCookieSharedOptions(),
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const setMedusaCustomerId = async (customerId: string) => {
|
||||
const cookies = await nextCookies()
|
||||
const cookies = await nextCookies();
|
||||
cookies.set(CookieName.MEDUSA_CUSTOMER_ID, customerId, {
|
||||
...getCookieSharedOptions(),
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const removeAuthToken = async () => {
|
||||
const cookies = await nextCookies()
|
||||
cookies.set(CookieName.MEDUSA_JWT, "", {
|
||||
const cookies = await nextCookies();
|
||||
cookies.set(CookieName.MEDUSA_JWT, '', {
|
||||
...getCookieResetOptions(),
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const getCartId = async () => {
|
||||
const cookies = await nextCookies()
|
||||
return cookies.get(CookieName.MEDUSA_CART_ID)?.value
|
||||
}
|
||||
const cookies = await nextCookies();
|
||||
return cookies.get(CookieName.MEDUSA_CART_ID)?.value;
|
||||
};
|
||||
|
||||
export const setCartId = async (cartId: string) => {
|
||||
const cookies = await nextCookies()
|
||||
const cookies = await nextCookies();
|
||||
cookies.set(CookieName.MEDUSA_CART_ID, cartId, {
|
||||
...getCookieSharedOptions(),
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const removeCartId = async () => {
|
||||
const cookies = await nextCookies()
|
||||
cookies.set(CookieName.MEDUSA_CART_ID, "", {
|
||||
const cookies = await nextCookies();
|
||||
cookies.set(CookieName.MEDUSA_CART_ID, '', {
|
||||
...getCookieResetOptions(),
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
"use server"
|
||||
'use server';
|
||||
|
||||
import { revalidateTag } from 'next/cache';
|
||||
|
||||
import { sdk } from '@lib/config';
|
||||
import medusaError from '@lib/util/medusa-error';
|
||||
import { HttpTypes } from '@medusajs/types';
|
||||
|
||||
import { sdk } from "@lib/config"
|
||||
import medusaError from "@lib/util/medusa-error"
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { revalidateTag } from "next/cache"
|
||||
import {
|
||||
getAuthHeaders,
|
||||
getCacheOptions,
|
||||
@@ -12,268 +14,275 @@ import {
|
||||
removeAuthToken,
|
||||
removeCartId,
|
||||
setAuthToken,
|
||||
} from "./cookies"
|
||||
} from './cookies';
|
||||
|
||||
export const retrieveCustomer =
|
||||
async (): Promise<HttpTypes.StoreCustomer | null> => {
|
||||
const authHeaders = await getAuthHeaders()
|
||||
const authHeaders = await getAuthHeaders();
|
||||
|
||||
if (!authHeaders) return null
|
||||
if (!authHeaders) return null;
|
||||
|
||||
const headers = {
|
||||
...authHeaders,
|
||||
}
|
||||
};
|
||||
|
||||
const next = {
|
||||
...(await getCacheOptions("customers")),
|
||||
}
|
||||
...(await getCacheOptions('customers')),
|
||||
};
|
||||
|
||||
return await sdk.client
|
||||
.fetch<{ customer: HttpTypes.StoreCustomer }>(`/store/customers/me`, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
query: {
|
||||
fields: "*orders",
|
||||
fields: '*orders',
|
||||
},
|
||||
headers,
|
||||
next,
|
||||
cache: "force-cache",
|
||||
cache: 'force-cache',
|
||||
})
|
||||
.then(({ customer }) => customer)
|
||||
.catch(() => null)
|
||||
}
|
||||
.catch(() => null);
|
||||
};
|
||||
|
||||
export const updateCustomer = async (body: HttpTypes.StoreUpdateCustomer) => {
|
||||
const headers = {
|
||||
...(await getAuthHeaders()),
|
||||
}
|
||||
};
|
||||
|
||||
const updateRes = await sdk.store.customer
|
||||
.update(body, {}, headers)
|
||||
.then(({ customer }) => customer)
|
||||
.catch(medusaError)
|
||||
.catch(medusaError);
|
||||
|
||||
const cacheTag = await getCacheTag("customers")
|
||||
revalidateTag(cacheTag)
|
||||
const cacheTag = await getCacheTag('customers');
|
||||
revalidateTag(cacheTag);
|
||||
|
||||
return updateRes
|
||||
}
|
||||
return updateRes;
|
||||
};
|
||||
|
||||
export async function signup(_currentState: unknown, formData: FormData) {
|
||||
const password = formData.get("password") as string
|
||||
const password = formData.get('password') as string;
|
||||
const customerForm = {
|
||||
email: formData.get("email") as string,
|
||||
first_name: formData.get("first_name") as string,
|
||||
last_name: formData.get("last_name") as string,
|
||||
phone: formData.get("phone") as string,
|
||||
}
|
||||
email: formData.get('email') as string,
|
||||
first_name: formData.get('first_name') as string,
|
||||
last_name: formData.get('last_name') as string,
|
||||
phone: formData.get('phone') as string,
|
||||
};
|
||||
|
||||
try {
|
||||
const token = await sdk.auth.register("customer", "emailpass", {
|
||||
const token = await sdk.auth.register('customer', 'emailpass', {
|
||||
email: customerForm.email,
|
||||
password: password,
|
||||
})
|
||||
});
|
||||
|
||||
await setAuthToken(token as string)
|
||||
await setAuthToken(token as string);
|
||||
|
||||
const headers = {
|
||||
...(await getAuthHeaders()),
|
||||
}
|
||||
};
|
||||
|
||||
const { customer: createdCustomer } = await sdk.store.customer.create(
|
||||
customerForm,
|
||||
{},
|
||||
headers
|
||||
)
|
||||
headers,
|
||||
);
|
||||
|
||||
const loginToken = await sdk.auth.login("customer", "emailpass", {
|
||||
const loginToken = await sdk.auth.login('customer', 'emailpass', {
|
||||
email: customerForm.email,
|
||||
password,
|
||||
})
|
||||
});
|
||||
|
||||
await setAuthToken(loginToken as string)
|
||||
await setAuthToken(loginToken as string);
|
||||
|
||||
const customerCacheTag = await getCacheTag("customers")
|
||||
revalidateTag(customerCacheTag)
|
||||
const customerCacheTag = await getCacheTag('customers');
|
||||
revalidateTag(customerCacheTag);
|
||||
|
||||
await transferCart()
|
||||
await transferCart();
|
||||
|
||||
return createdCustomer
|
||||
return createdCustomer;
|
||||
} catch (error: any) {
|
||||
return error.toString()
|
||||
return error.toString();
|
||||
}
|
||||
}
|
||||
|
||||
export async function login(_currentState: unknown, formData: FormData) {
|
||||
const email = formData.get("email") as string
|
||||
const password = formData.get("password") as string
|
||||
const email = formData.get('email') as string;
|
||||
const password = formData.get('password') as string;
|
||||
|
||||
try {
|
||||
await sdk.auth
|
||||
.login("customer", "emailpass", { email, password })
|
||||
.login('customer', 'emailpass', { email, password })
|
||||
.then(async (token) => {
|
||||
await setAuthToken(token as string)
|
||||
const customerCacheTag = await getCacheTag("customers")
|
||||
revalidateTag(customerCacheTag)
|
||||
})
|
||||
await setAuthToken(token as string);
|
||||
const customerCacheTag = await getCacheTag('customers');
|
||||
revalidateTag(customerCacheTag);
|
||||
});
|
||||
} catch (error: any) {
|
||||
return error.toString()
|
||||
return error.toString();
|
||||
}
|
||||
|
||||
try {
|
||||
await transferCart()
|
||||
await transferCart();
|
||||
} catch (error: any) {
|
||||
return error.toString()
|
||||
return error.toString();
|
||||
}
|
||||
}
|
||||
|
||||
export async function medusaLogout(countryCode = 'ee', canRevalidateTags = true) {
|
||||
await sdk.auth.logout()
|
||||
export async function medusaLogout(
|
||||
countryCode = 'ee',
|
||||
canRevalidateTags = true,
|
||||
) {
|
||||
await sdk.auth.logout();
|
||||
|
||||
await removeAuthToken()
|
||||
await removeAuthToken();
|
||||
|
||||
if (canRevalidateTags) {
|
||||
const customerCacheTag = await getCacheTag("customers")
|
||||
revalidateTag(customerCacheTag)
|
||||
const customerCacheTag = await getCacheTag('customers');
|
||||
revalidateTag(customerCacheTag);
|
||||
}
|
||||
|
||||
await removeCartId()
|
||||
await removeCartId();
|
||||
|
||||
if (canRevalidateTags) {
|
||||
const cartCacheTag = await getCacheTag("carts")
|
||||
revalidateTag(cartCacheTag)
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
}
|
||||
}
|
||||
|
||||
export async function transferCart() {
|
||||
const cartId = await getCartId()
|
||||
const cartId = await getCartId();
|
||||
|
||||
if (!cartId) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = await getAuthHeaders()
|
||||
const headers = await getAuthHeaders();
|
||||
|
||||
await sdk.store.cart.transferCart(cartId, {}, headers)
|
||||
await sdk.store.cart.transferCart(cartId, {}, headers);
|
||||
|
||||
const cartCacheTag = await getCacheTag("carts")
|
||||
revalidateTag(cartCacheTag)
|
||||
const cartCacheTag = await getCacheTag('carts');
|
||||
revalidateTag(cartCacheTag);
|
||||
}
|
||||
|
||||
export const addCustomerAddress = async (
|
||||
currentState: Record<string, unknown>,
|
||||
formData: FormData
|
||||
formData: FormData,
|
||||
): Promise<any> => {
|
||||
const isDefaultBilling = (currentState.isDefaultBilling as boolean) || false
|
||||
const isDefaultShipping = (currentState.isDefaultShipping as boolean) || false
|
||||
const isDefaultBilling = (currentState.isDefaultBilling as boolean) || false;
|
||||
const isDefaultShipping =
|
||||
(currentState.isDefaultShipping as boolean) || false;
|
||||
|
||||
const address = {
|
||||
first_name: formData.get("first_name") as string,
|
||||
last_name: formData.get("last_name") as string,
|
||||
company: formData.get("company") as string,
|
||||
address_1: formData.get("address_1") as string,
|
||||
address_2: formData.get("address_2") as string,
|
||||
city: formData.get("city") as string,
|
||||
postal_code: formData.get("postal_code") as string,
|
||||
province: formData.get("province") as string,
|
||||
country_code: formData.get("country_code") as string,
|
||||
phone: formData.get("phone") as string,
|
||||
first_name: formData.get('first_name') as string,
|
||||
last_name: formData.get('last_name') as string,
|
||||
company: formData.get('company') as string,
|
||||
address_1: formData.get('address_1') as string,
|
||||
address_2: formData.get('address_2') as string,
|
||||
city: formData.get('city') as string,
|
||||
postal_code: formData.get('postal_code') as string,
|
||||
province: formData.get('province') as string,
|
||||
country_code: formData.get('country_code') as string,
|
||||
phone: formData.get('phone') as string,
|
||||
is_default_billing: isDefaultBilling,
|
||||
is_default_shipping: isDefaultShipping,
|
||||
}
|
||||
};
|
||||
|
||||
const headers = {
|
||||
...(await getAuthHeaders()),
|
||||
}
|
||||
};
|
||||
|
||||
return sdk.store.customer
|
||||
.createAddress(address, {}, headers)
|
||||
.then(async ({ customer }) => {
|
||||
const customerCacheTag = await getCacheTag("customers")
|
||||
revalidateTag(customerCacheTag)
|
||||
return { success: true, error: null }
|
||||
const customerCacheTag = await getCacheTag('customers');
|
||||
revalidateTag(customerCacheTag);
|
||||
return { success: true, error: null };
|
||||
})
|
||||
.catch((err) => {
|
||||
return { success: false, error: err.toString() }
|
||||
})
|
||||
}
|
||||
return { success: false, error: err.toString() };
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteCustomerAddress = async (
|
||||
addressId: string
|
||||
addressId: string,
|
||||
): Promise<void> => {
|
||||
const headers = {
|
||||
...(await getAuthHeaders()),
|
||||
}
|
||||
};
|
||||
|
||||
await sdk.store.customer
|
||||
.deleteAddress(addressId, headers)
|
||||
.then(async () => {
|
||||
const customerCacheTag = await getCacheTag("customers")
|
||||
revalidateTag(customerCacheTag)
|
||||
return { success: true, error: null }
|
||||
const customerCacheTag = await getCacheTag('customers');
|
||||
revalidateTag(customerCacheTag);
|
||||
return { success: true, error: null };
|
||||
})
|
||||
.catch((err) => {
|
||||
return { success: false, error: err.toString() }
|
||||
})
|
||||
}
|
||||
return { success: false, error: err.toString() };
|
||||
});
|
||||
};
|
||||
|
||||
export const updateCustomerAddress = async (
|
||||
currentState: Record<string, unknown>,
|
||||
formData: FormData
|
||||
formData: FormData,
|
||||
): Promise<any> => {
|
||||
const addressId =
|
||||
(currentState.addressId as string) || (formData.get("addressId") as string)
|
||||
(currentState.addressId as string) || (formData.get('addressId') as string);
|
||||
|
||||
if (!addressId) {
|
||||
return { success: false, error: "Address ID is required" }
|
||||
return { success: false, error: 'Address ID is required' };
|
||||
}
|
||||
|
||||
const address = {
|
||||
first_name: formData.get("first_name") as string,
|
||||
last_name: formData.get("last_name") as string,
|
||||
company: formData.get("company") as string,
|
||||
address_1: formData.get("address_1") as string,
|
||||
address_2: formData.get("address_2") as string,
|
||||
city: formData.get("city") as string,
|
||||
postal_code: formData.get("postal_code") as string,
|
||||
province: formData.get("province") as string,
|
||||
country_code: formData.get("country_code") as string,
|
||||
} as HttpTypes.StoreUpdateCustomerAddress
|
||||
first_name: formData.get('first_name') as string,
|
||||
last_name: formData.get('last_name') as string,
|
||||
company: formData.get('company') as string,
|
||||
address_1: formData.get('address_1') as string,
|
||||
address_2: formData.get('address_2') as string,
|
||||
city: formData.get('city') as string,
|
||||
postal_code: formData.get('postal_code') as string,
|
||||
province: formData.get('province') as string,
|
||||
country_code: formData.get('country_code') as string,
|
||||
} as HttpTypes.StoreUpdateCustomerAddress;
|
||||
|
||||
const phone = formData.get("phone") as string
|
||||
const phone = formData.get('phone') as string;
|
||||
|
||||
if (phone) {
|
||||
address.phone = phone
|
||||
address.phone = phone;
|
||||
}
|
||||
|
||||
const headers = {
|
||||
...(await getAuthHeaders()),
|
||||
}
|
||||
};
|
||||
|
||||
return sdk.store.customer
|
||||
.updateAddress(addressId, address, {}, headers)
|
||||
.then(async () => {
|
||||
const customerCacheTag = await getCacheTag("customers")
|
||||
revalidateTag(customerCacheTag)
|
||||
return { success: true, error: null }
|
||||
const customerCacheTag = await getCacheTag('customers');
|
||||
revalidateTag(customerCacheTag);
|
||||
return { success: true, error: null };
|
||||
})
|
||||
.catch((err) => {
|
||||
return { success: false, error: err.toString() }
|
||||
})
|
||||
}
|
||||
return { success: false, error: err.toString() };
|
||||
});
|
||||
};
|
||||
|
||||
async function medusaLogin(email: string, password: string) {
|
||||
const token = await sdk.auth.login("customer", "emailpass", { email, password });
|
||||
const token = await sdk.auth.login('customer', 'emailpass', {
|
||||
email,
|
||||
password,
|
||||
});
|
||||
await setAuthToken(token as string);
|
||||
|
||||
try {
|
||||
await transferCart();
|
||||
} catch (e) {
|
||||
console.error("Failed to transfer cart", e);
|
||||
console.error('Failed to transfer cart', e);
|
||||
}
|
||||
|
||||
const customer = await retrieveCustomer();
|
||||
if (!customer) {
|
||||
throw new Error("Customer not found for active session");
|
||||
throw new Error('Customer not found for active session');
|
||||
}
|
||||
|
||||
return customer.id;
|
||||
@@ -290,29 +299,41 @@ async function medusaRegister({
|
||||
name: string | undefined;
|
||||
lastName: string | undefined;
|
||||
}) {
|
||||
console.info(`Creating new Medusa account for Keycloak user with email=${email}`);
|
||||
|
||||
const registerToken = await sdk.auth.register("customer", "emailpass", { email, password });
|
||||
console.info(
|
||||
`Creating new Medusa account for Keycloak user with email=${email}`,
|
||||
);
|
||||
|
||||
const registerToken = await sdk.auth.register('customer', 'emailpass', {
|
||||
email,
|
||||
password,
|
||||
});
|
||||
await setAuthToken(registerToken);
|
||||
|
||||
console.info(`Creating new Medusa customer profile for Keycloak user with email=${email} and name=${name} and lastName=${lastName}`);
|
||||
console.info(
|
||||
`Creating new Medusa customer profile for Keycloak user with email=${email} and name=${name} and lastName=${lastName}`,
|
||||
);
|
||||
await sdk.store.customer.create(
|
||||
{ email, first_name: name, last_name: lastName },
|
||||
{},
|
||||
{
|
||||
...(await getAuthHeaders()),
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export async function medusaLoginOrRegister(credentials: {
|
||||
email: string
|
||||
supabaseUserId?: string
|
||||
name?: string,
|
||||
lastName?: string,
|
||||
} & ({ isDevPasswordLogin: true; password: string } | { isDevPasswordLogin?: false; password?: undefined })) {
|
||||
export async function medusaLoginOrRegister(
|
||||
credentials: {
|
||||
email: string;
|
||||
supabaseUserId?: string;
|
||||
name?: string;
|
||||
lastName?: string;
|
||||
} & (
|
||||
| { isDevPasswordLogin: true; password: string }
|
||||
| { isDevPasswordLogin?: false; password?: undefined }
|
||||
),
|
||||
) {
|
||||
const { email, supabaseUserId, name, lastName } = credentials;
|
||||
|
||||
|
||||
const password = await (async () => {
|
||||
if (credentials.isDevPasswordLogin) {
|
||||
return credentials.password;
|
||||
@@ -324,13 +345,19 @@ export async function medusaLoginOrRegister(credentials: {
|
||||
try {
|
||||
return await medusaLogin(email, password);
|
||||
} catch (loginError) {
|
||||
console.error("Failed to login customer, attempting to register", loginError);
|
||||
console.error(
|
||||
'Failed to login customer, attempting to register',
|
||||
loginError,
|
||||
);
|
||||
|
||||
try {
|
||||
await medusaRegister({ email, password, name, lastName });
|
||||
return await medusaLogin(email, password);
|
||||
} catch (registerError) {
|
||||
console.error("Failed to create Medusa account for user with email=${email}", registerError);
|
||||
console.error(
|
||||
'Failed to create Medusa account for user with email=${email}',
|
||||
registerError,
|
||||
);
|
||||
throw medusaError(registerError);
|
||||
}
|
||||
}
|
||||
@@ -340,7 +367,10 @@ export async function medusaLoginOrRegister(credentials: {
|
||||
* Generate a deterministic password based on user identifier
|
||||
* This ensures the same user always gets the same password for Medusa
|
||||
*/
|
||||
async function generateDeterministicPassword(email: string, userId?: string): Promise<string> {
|
||||
async function generateDeterministicPassword(
|
||||
email: string,
|
||||
userId?: string,
|
||||
): Promise<string> {
|
||||
// Use the user ID or email as the base for deterministic generation
|
||||
const baseString = userId || email;
|
||||
const secret = process.env.MEDUSA_PASSWORD_SECRET!;
|
||||
@@ -356,13 +386,15 @@ async function generateDeterministicPassword(email: string, userId?: string): Pr
|
||||
keyData,
|
||||
{ name: 'HMAC', hash: 'SHA-256' },
|
||||
false,
|
||||
['sign']
|
||||
['sign'],
|
||||
);
|
||||
// Generate HMAC
|
||||
const signature = await crypto.subtle.sign('HMAC', key, messageData);
|
||||
// Convert to base64 and make it a valid password
|
||||
const hashArray = Array.from(new Uint8Array(signature));
|
||||
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
const hashHex = hashArray
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('');
|
||||
// Take first 24 characters and add some complexity
|
||||
const basePassword = hashHex.substring(0, 24);
|
||||
// Add some required complexity for Medusa (uppercase, lowercase, numbers, symbols)
|
||||
|
||||
@@ -1,70 +1,71 @@
|
||||
"use server"
|
||||
'use server';
|
||||
|
||||
import { sdk } from "@lib/config"
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { getAuthHeaders, getCacheOptions } from "./cookies"
|
||||
import { sdk } from '@lib/config';
|
||||
import { HttpTypes } from '@medusajs/types';
|
||||
|
||||
import { getAuthHeaders, getCacheOptions } from './cookies';
|
||||
|
||||
export const listCartShippingMethods = async (cartId: string) => {
|
||||
const headers = {
|
||||
...(await getAuthHeaders()),
|
||||
}
|
||||
};
|
||||
|
||||
const next = {
|
||||
...(await getCacheOptions("fulfillment")),
|
||||
}
|
||||
...(await getCacheOptions('fulfillment')),
|
||||
};
|
||||
|
||||
return sdk.client
|
||||
.fetch<HttpTypes.StoreShippingOptionListResponse>(
|
||||
`/store/shipping-options`,
|
||||
{
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
query: {
|
||||
cart_id: cartId,
|
||||
fields:
|
||||
"+service_zone.fulfllment_set.type,*service_zone.fulfillment_set.location.address",
|
||||
'+service_zone.fulfllment_set.type,*service_zone.fulfillment_set.location.address',
|
||||
},
|
||||
headers,
|
||||
next,
|
||||
cache: "force-cache",
|
||||
}
|
||||
cache: 'force-cache',
|
||||
},
|
||||
)
|
||||
.then(({ shipping_options }) => shipping_options)
|
||||
.catch(() => {
|
||||
return null
|
||||
})
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
export const calculatePriceForShippingOption = async (
|
||||
optionId: string,
|
||||
cartId: string,
|
||||
data?: Record<string, unknown>
|
||||
data?: Record<string, unknown>,
|
||||
) => {
|
||||
const headers = {
|
||||
...(await getAuthHeaders()),
|
||||
}
|
||||
};
|
||||
|
||||
const next = {
|
||||
...(await getCacheOptions("fulfillment")),
|
||||
}
|
||||
...(await getCacheOptions('fulfillment')),
|
||||
};
|
||||
|
||||
const body = { cart_id: cartId, data }
|
||||
const body = { cart_id: cartId, data };
|
||||
|
||||
if (data) {
|
||||
body.data = data
|
||||
body.data = data;
|
||||
}
|
||||
|
||||
return sdk.client
|
||||
.fetch<{ shipping_option: HttpTypes.StoreCartShippingOption }>(
|
||||
`/store/shipping-options/${optionId}/calculate`,
|
||||
{
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
body,
|
||||
headers,
|
||||
next,
|
||||
}
|
||||
},
|
||||
)
|
||||
.then(({ shipping_option }) => shipping_option)
|
||||
.catch((e) => {
|
||||
return null
|
||||
})
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export * from "./cart";
|
||||
export * from "./categories";
|
||||
export * from "./collections";
|
||||
export * from "./cookies";
|
||||
export * from "./customer";
|
||||
export * from "./fulfillment";
|
||||
export * from "./onboarding";
|
||||
export * from "./orders";
|
||||
export * from "./payment";
|
||||
export * from "./products";
|
||||
export * from "./regions";
|
||||
export * from './cart';
|
||||
export * from './categories';
|
||||
export * from './collections';
|
||||
export * from './cookies';
|
||||
export * from './customer';
|
||||
export * from './fulfillment';
|
||||
export * from './onboarding';
|
||||
export * from './orders';
|
||||
export * from './payment';
|
||||
export * from './products';
|
||||
export * from './regions';
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
"use server"
|
||||
import { cookies as nextCookies } from "next/headers"
|
||||
import { redirect } from "next/navigation"
|
||||
'use server';
|
||||
|
||||
import { cookies as nextCookies } from 'next/headers';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export async function resetOnboardingState(orderId: string) {
|
||||
const cookies = await nextCookies()
|
||||
cookies.set("_medusa_onboarding", "false", { maxAge: -1 })
|
||||
redirect(`http://localhost:7001/a/orders/${orderId}`)
|
||||
const cookies = await nextCookies();
|
||||
cookies.set('_medusa_onboarding', 'false', { maxAge: -1 });
|
||||
redirect(`http://localhost:7001/a/orders/${orderId}`);
|
||||
}
|
||||
|
||||
@@ -1,111 +1,112 @@
|
||||
"use server"
|
||||
'use server';
|
||||
|
||||
import { sdk } from "@lib/config"
|
||||
import medusaError from "@lib/util/medusa-error"
|
||||
import { getAuthHeaders, getCacheOptions } from "./cookies"
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { sdk } from '@lib/config';
|
||||
import medusaError from '@lib/util/medusa-error';
|
||||
import { HttpTypes } from '@medusajs/types';
|
||||
|
||||
import { getAuthHeaders, getCacheOptions } from './cookies';
|
||||
|
||||
export const retrieveOrder = async (id: string) => {
|
||||
const headers = {
|
||||
...(await getAuthHeaders()),
|
||||
}
|
||||
};
|
||||
|
||||
const next = {
|
||||
...(await getCacheOptions("orders")),
|
||||
}
|
||||
...(await getCacheOptions('orders')),
|
||||
};
|
||||
|
||||
return sdk.client
|
||||
.fetch<HttpTypes.StoreOrderResponse>(`/store/orders/${id}`, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
query: {
|
||||
fields:
|
||||
"*payment_collections.payments,*items,*items.metadata,*items.variant,*items.product",
|
||||
'*payment_collections.payments,*items,*items.metadata,*items.variant,*items.product',
|
||||
},
|
||||
headers,
|
||||
next,
|
||||
cache: "force-cache",
|
||||
cache: 'force-cache',
|
||||
})
|
||||
.then(({ order }) => order)
|
||||
.catch((err) => medusaError(err))
|
||||
}
|
||||
.catch((err) => medusaError(err));
|
||||
};
|
||||
|
||||
export const listOrders = async (
|
||||
limit: number = 10,
|
||||
offset: number = 0,
|
||||
filters?: Record<string, any>
|
||||
filters?: Record<string, any>,
|
||||
) => {
|
||||
const headers = {
|
||||
...(await getAuthHeaders()),
|
||||
}
|
||||
};
|
||||
|
||||
const next = {
|
||||
...(await getCacheOptions("orders")),
|
||||
}
|
||||
...(await getCacheOptions('orders')),
|
||||
};
|
||||
|
||||
return sdk.client
|
||||
.fetch<HttpTypes.StoreOrderListResponse>(`/store/orders`, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
query: {
|
||||
limit,
|
||||
offset,
|
||||
order: "-created_at",
|
||||
fields: "*items,+items.metadata,*items.variant,*items.product",
|
||||
order: '-created_at',
|
||||
fields: '*items,+items.metadata,*items.variant,*items.product',
|
||||
...filters,
|
||||
},
|
||||
headers,
|
||||
next,
|
||||
})
|
||||
.then(({ orders }) => orders)
|
||||
.catch((err) => medusaError(err))
|
||||
}
|
||||
.catch((err) => medusaError(err));
|
||||
};
|
||||
|
||||
export const createTransferRequest = async (
|
||||
state: {
|
||||
success: boolean
|
||||
error: string | null
|
||||
order: HttpTypes.StoreOrder | null
|
||||
success: boolean;
|
||||
error: string | null;
|
||||
order: HttpTypes.StoreOrder | null;
|
||||
},
|
||||
formData: FormData
|
||||
formData: FormData,
|
||||
): Promise<{
|
||||
success: boolean
|
||||
error: string | null
|
||||
order: HttpTypes.StoreOrder | null
|
||||
success: boolean;
|
||||
error: string | null;
|
||||
order: HttpTypes.StoreOrder | null;
|
||||
}> => {
|
||||
const id = formData.get("order_id") as string
|
||||
const id = formData.get('order_id') as string;
|
||||
|
||||
if (!id) {
|
||||
return { success: false, error: "Order ID is required", order: null }
|
||||
return { success: false, error: 'Order ID is required', order: null };
|
||||
}
|
||||
|
||||
const headers = await getAuthHeaders()
|
||||
const headers = await getAuthHeaders();
|
||||
|
||||
return await sdk.store.order
|
||||
.requestTransfer(
|
||||
id,
|
||||
{},
|
||||
{
|
||||
fields: "id, email",
|
||||
fields: 'id, email',
|
||||
},
|
||||
headers
|
||||
headers,
|
||||
)
|
||||
.then(({ order }) => ({ success: true, error: null, order }))
|
||||
.catch((err) => ({ success: false, error: err.message, order: null }))
|
||||
}
|
||||
.catch((err) => ({ success: false, error: err.message, order: null }));
|
||||
};
|
||||
|
||||
export const acceptTransferRequest = async (id: string, token: string) => {
|
||||
const headers = await getAuthHeaders()
|
||||
const headers = await getAuthHeaders();
|
||||
|
||||
return await sdk.store.order
|
||||
.acceptTransfer(id, { token }, {}, headers)
|
||||
.then(({ order }) => ({ success: true, error: null, order }))
|
||||
.catch((err) => ({ success: false, error: err.message, order: null }))
|
||||
}
|
||||
.catch((err) => ({ success: false, error: err.message, order: null }));
|
||||
};
|
||||
|
||||
export const declineTransferRequest = async (id: string, token: string) => {
|
||||
const headers = await getAuthHeaders()
|
||||
const headers = await getAuthHeaders();
|
||||
|
||||
return await sdk.store.order
|
||||
.declineTransfer(id, { token }, {}, headers)
|
||||
.then(({ order }) => ({ success: true, error: null, order }))
|
||||
.catch((err) => ({ success: false, error: err.message, order: null }))
|
||||
}
|
||||
.catch((err) => ({ success: false, error: err.message, order: null }));
|
||||
};
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
"use server"
|
||||
'use server';
|
||||
|
||||
import { sdk } from "@lib/config"
|
||||
import { getAuthHeaders, getCacheOptions } from "./cookies"
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { sdk } from '@lib/config';
|
||||
import { HttpTypes } from '@medusajs/types';
|
||||
|
||||
import { getAuthHeaders, getCacheOptions } from './cookies';
|
||||
|
||||
export const listCartPaymentMethods = async (regionId: string) => {
|
||||
const headers = {
|
||||
...(await getAuthHeaders()),
|
||||
}
|
||||
};
|
||||
|
||||
const next = {
|
||||
...(await getCacheOptions("payment_providers")),
|
||||
}
|
||||
...(await getCacheOptions('payment_providers')),
|
||||
};
|
||||
|
||||
return sdk.client
|
||||
.fetch<HttpTypes.StorePaymentProviderListResponse>(
|
||||
`/store/payment-providers`,
|
||||
{
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
query: { region_id: regionId },
|
||||
headers,
|
||||
next,
|
||||
cache: "force-cache",
|
||||
}
|
||||
cache: 'force-cache',
|
||||
},
|
||||
)
|
||||
.then(({ payment_providers }) =>
|
||||
payment_providers.sort((a, b) => {
|
||||
return a.id > b.id ? 1 : -1
|
||||
})
|
||||
return a.id > b.id ? 1 : -1;
|
||||
}),
|
||||
)
|
||||
.catch(() => {
|
||||
return null
|
||||
})
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
"use server"
|
||||
'use server';
|
||||
|
||||
import { sdk } from "@lib/config"
|
||||
import { sortProducts } from "@lib/util/sort-products"
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { SortOptions } from "@modules/store/components/refinement-list/sort-products"
|
||||
import { getAuthHeaders, getCacheOptions } from "./cookies"
|
||||
import { getRegion, retrieveRegion } from "./regions"
|
||||
import { sdk } from '@lib/config';
|
||||
import { sortProducts } from '@lib/util/sort-products';
|
||||
import { HttpTypes } from '@medusajs/types';
|
||||
import { SortOptions } from '@modules/store/components/refinement-list/sort-products';
|
||||
|
||||
import { getAuthHeaders, getCacheOptions } from './cookies';
|
||||
import { getRegion, retrieveRegion } from './regions';
|
||||
|
||||
export const listProducts = async ({
|
||||
pageParam = 1,
|
||||
@@ -13,70 +14,71 @@ export const listProducts = async ({
|
||||
countryCode,
|
||||
regionId,
|
||||
}: {
|
||||
pageParam?: number
|
||||
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams & {
|
||||
"type_id[0]"?: string;
|
||||
id?: string[],
|
||||
category_id?: string;
|
||||
order?: 'title';
|
||||
}
|
||||
countryCode?: string
|
||||
regionId?: string
|
||||
pageParam?: number;
|
||||
queryParams?: HttpTypes.FindParams &
|
||||
HttpTypes.StoreProductParams & {
|
||||
'type_id[0]'?: string;
|
||||
id?: string[];
|
||||
category_id?: string;
|
||||
order?: 'title';
|
||||
};
|
||||
countryCode?: string;
|
||||
regionId?: string;
|
||||
}): Promise<{
|
||||
response: { products: HttpTypes.StoreProduct[]; count: number }
|
||||
nextPage: number | null
|
||||
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams
|
||||
response: { products: HttpTypes.StoreProduct[]; count: number };
|
||||
nextPage: number | null;
|
||||
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams;
|
||||
}> => {
|
||||
if (!countryCode && !regionId) {
|
||||
throw new Error("Country code or region ID is required")
|
||||
throw new Error('Country code or region ID is required');
|
||||
}
|
||||
|
||||
const limit = queryParams?.limit || 12
|
||||
const _pageParam = Math.max(pageParam, 1)
|
||||
const offset = (_pageParam === 1) ? 0 : (_pageParam - 1) * limit;
|
||||
const limit = queryParams?.limit || 12;
|
||||
const _pageParam = Math.max(pageParam, 1);
|
||||
const offset = _pageParam === 1 ? 0 : (_pageParam - 1) * limit;
|
||||
|
||||
let region: HttpTypes.StoreRegion | undefined | null
|
||||
let region: HttpTypes.StoreRegion | undefined | null;
|
||||
|
||||
if (countryCode) {
|
||||
region = await getRegion(countryCode)
|
||||
region = await getRegion(countryCode);
|
||||
} else {
|
||||
region = await retrieveRegion(regionId!)
|
||||
region = await retrieveRegion(regionId!);
|
||||
}
|
||||
|
||||
if (!region) {
|
||||
return {
|
||||
response: { products: [], count: 0 },
|
||||
nextPage: null,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const headers = {
|
||||
...(await getAuthHeaders()),
|
||||
}
|
||||
};
|
||||
|
||||
const next = {
|
||||
...(await getCacheOptions("products")),
|
||||
}
|
||||
...(await getCacheOptions('products')),
|
||||
};
|
||||
|
||||
return sdk.client
|
||||
.fetch<{ products: HttpTypes.StoreProduct[]; count: number }>(
|
||||
`/store/products`,
|
||||
{
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
query: {
|
||||
limit,
|
||||
offset,
|
||||
region_id: region?.id,
|
||||
fields:
|
||||
"*variants.calculated_price,+variants.inventory_quantity,+metadata,+tags,+status",
|
||||
'*variants.calculated_price,+variants.inventory_quantity,+metadata,+tags,+status',
|
||||
...queryParams,
|
||||
},
|
||||
headers,
|
||||
next,
|
||||
}
|
||||
},
|
||||
)
|
||||
.then(({ products, count }) => {
|
||||
const nextPage = count > offset + limit ? pageParam + 1 : null
|
||||
const nextPage = count > offset + limit ? pageParam + 1 : null;
|
||||
|
||||
return {
|
||||
response: {
|
||||
@@ -85,9 +87,9 @@ export const listProducts = async ({
|
||||
},
|
||||
nextPage: nextPage,
|
||||
queryParams,
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* This will fetch 100 products to the Next.js cache and sort them based on the sortBy parameter.
|
||||
@@ -96,19 +98,19 @@ export const listProducts = async ({
|
||||
export const listProductsWithSort = async ({
|
||||
page = 0,
|
||||
queryParams,
|
||||
sortBy = "created_at",
|
||||
sortBy = 'created_at',
|
||||
countryCode,
|
||||
}: {
|
||||
page?: number
|
||||
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams
|
||||
sortBy?: SortOptions
|
||||
countryCode: string
|
||||
page?: number;
|
||||
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams;
|
||||
sortBy?: SortOptions;
|
||||
countryCode: string;
|
||||
}): Promise<{
|
||||
response: { products: HttpTypes.StoreProduct[]; count: number }
|
||||
nextPage: number | null
|
||||
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams
|
||||
response: { products: HttpTypes.StoreProduct[]; count: number };
|
||||
nextPage: number | null;
|
||||
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams;
|
||||
}> => {
|
||||
const limit = queryParams?.limit || 12
|
||||
const limit = queryParams?.limit || 12;
|
||||
|
||||
const {
|
||||
response: { products, count },
|
||||
@@ -119,15 +121,15 @@ export const listProductsWithSort = async ({
|
||||
limit: 100,
|
||||
},
|
||||
countryCode,
|
||||
})
|
||||
});
|
||||
|
||||
const sortedProducts = sortProducts(products, sortBy)
|
||||
const sortedProducts = sortProducts(products, sortBy);
|
||||
|
||||
const pageParam = (page - 1) * limit
|
||||
const pageParam = (page - 1) * limit;
|
||||
|
||||
const nextPage = count > pageParam + limit ? pageParam + limit : null
|
||||
const nextPage = count > pageParam + limit ? pageParam + limit : null;
|
||||
|
||||
const paginatedProducts = sortedProducts.slice(pageParam, pageParam + limit)
|
||||
const paginatedProducts = sortedProducts.slice(pageParam, pageParam + limit);
|
||||
|
||||
return {
|
||||
response: {
|
||||
@@ -136,24 +138,27 @@ export const listProductsWithSort = async ({
|
||||
},
|
||||
nextPage,
|
||||
queryParams,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const listProductTypes = async (): Promise<{ productTypes: HttpTypes.StoreProductType[]; count: number }> => {
|
||||
export const listProductTypes = async (): Promise<{
|
||||
productTypes: HttpTypes.StoreProductType[];
|
||||
count: number;
|
||||
}> => {
|
||||
const next = {
|
||||
...(await getCacheOptions("productTypes")),
|
||||
...(await getCacheOptions('productTypes')),
|
||||
};
|
||||
|
||||
return sdk.client
|
||||
.fetch<{ product_types: HttpTypes.StoreProductType[]; count: number }>(
|
||||
"/store/product-types",
|
||||
'/store/product-types',
|
||||
{
|
||||
next,
|
||||
//cache: "force-cache",
|
||||
query: {
|
||||
fields: "id,value,metadata",
|
||||
fields: 'id,value,metadata',
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
.then(({ product_types, count }) => {
|
||||
return { productTypes: product_types, count };
|
||||
|
||||
@@ -1,66 +1,67 @@
|
||||
"use server"
|
||||
'use server';
|
||||
|
||||
import { sdk } from "@lib/config"
|
||||
import medusaError from "@lib/util/medusa-error"
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { getCacheOptions } from "./cookies"
|
||||
import { sdk } from '@lib/config';
|
||||
import medusaError from '@lib/util/medusa-error';
|
||||
import { HttpTypes } from '@medusajs/types';
|
||||
|
||||
import { getCacheOptions } from './cookies';
|
||||
|
||||
export const listRegions = async () => {
|
||||
const next = {
|
||||
...(await getCacheOptions("regions")),
|
||||
}
|
||||
...(await getCacheOptions('regions')),
|
||||
};
|
||||
|
||||
return sdk.client
|
||||
.fetch<{ regions: HttpTypes.StoreRegion[] }>(`/store/regions`, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
next,
|
||||
cache: "force-cache",
|
||||
cache: 'force-cache',
|
||||
})
|
||||
.then(({ regions }) => regions)
|
||||
.catch(medusaError)
|
||||
}
|
||||
.catch(medusaError);
|
||||
};
|
||||
|
||||
export const retrieveRegion = async (id: string) => {
|
||||
const next = {
|
||||
...(await getCacheOptions(["regions", id].join("-"))),
|
||||
}
|
||||
...(await getCacheOptions(['regions', id].join('-'))),
|
||||
};
|
||||
|
||||
return sdk.client
|
||||
.fetch<{ region: HttpTypes.StoreRegion }>(`/store/regions/${id}`, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
next,
|
||||
cache: "force-cache",
|
||||
cache: 'force-cache',
|
||||
})
|
||||
.then(({ region }) => region)
|
||||
.catch(medusaError)
|
||||
}
|
||||
.catch(medusaError);
|
||||
};
|
||||
|
||||
const regionMap = new Map<string, HttpTypes.StoreRegion>()
|
||||
const regionMap = new Map<string, HttpTypes.StoreRegion>();
|
||||
|
||||
export const getRegion = async (countryCode: string) => {
|
||||
try {
|
||||
if (regionMap.has(countryCode)) {
|
||||
return regionMap.get(countryCode)
|
||||
return regionMap.get(countryCode);
|
||||
}
|
||||
|
||||
const regions = await listRegions()
|
||||
const regions = await listRegions();
|
||||
|
||||
if (!regions) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
regions.forEach((region) => {
|
||||
region.countries?.forEach((c) => {
|
||||
regionMap.set(c?.iso_2 ?? "", region)
|
||||
})
|
||||
})
|
||||
regionMap.set(c?.iso_2 ?? '', region);
|
||||
});
|
||||
});
|
||||
|
||||
const region = countryCode
|
||||
? regionMap.get(countryCode)
|
||||
: regionMap.get("et")
|
||||
: regionMap.get('et');
|
||||
|
||||
return region
|
||||
return region;
|
||||
} catch (e: any) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import { RefObject, useEffect, useState } from "react"
|
||||
import { RefObject, useEffect, useState } from 'react';
|
||||
|
||||
export const useIntersection = (
|
||||
element: RefObject<HTMLDivElement | null>,
|
||||
rootMargin: string
|
||||
rootMargin: string,
|
||||
) => {
|
||||
const [isVisible, setState] = useState(false)
|
||||
const [isVisible, setState] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!element.current) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const el = element.current
|
||||
const el = element.current;
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
setState(entry.isIntersecting)
|
||||
setState(entry.isIntersecting);
|
||||
},
|
||||
{ rootMargin }
|
||||
)
|
||||
{ rootMargin },
|
||||
);
|
||||
|
||||
observer.observe(el)
|
||||
observer.observe(el);
|
||||
|
||||
return () => observer.unobserve(el)
|
||||
}, [element, rootMargin])
|
||||
return () => observer.unobserve(el);
|
||||
}, [element, rootMargin]);
|
||||
|
||||
return isVisible
|
||||
}
|
||||
return isVisible;
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useState } from "react"
|
||||
import { useState } from 'react';
|
||||
|
||||
export type StateType = [boolean, () => void, () => void, () => void] & {
|
||||
state: boolean
|
||||
open: () => void
|
||||
close: () => void
|
||||
toggle: () => void
|
||||
}
|
||||
state: boolean;
|
||||
open: () => void;
|
||||
close: () => void;
|
||||
toggle: () => void;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -21,26 +21,26 @@ export type StateType = [boolean, () => void, () => void, () => void] & {
|
||||
*/
|
||||
|
||||
const useToggleState = (initialState = false) => {
|
||||
const [state, setState] = useState<boolean>(initialState)
|
||||
const [state, setState] = useState<boolean>(initialState);
|
||||
|
||||
const close = () => {
|
||||
setState(false)
|
||||
}
|
||||
setState(false);
|
||||
};
|
||||
|
||||
const open = () => {
|
||||
setState(true)
|
||||
}
|
||||
setState(true);
|
||||
};
|
||||
|
||||
const toggle = () => {
|
||||
setState((state) => !state)
|
||||
}
|
||||
setState((state) => !state);
|
||||
};
|
||||
|
||||
const hookData = [state, open, close, toggle] as StateType
|
||||
hookData.state = state
|
||||
hookData.open = open
|
||||
hookData.close = close
|
||||
hookData.toggle = toggle
|
||||
return hookData
|
||||
}
|
||||
const hookData = [state, open, close, toggle] as StateType;
|
||||
hookData.state = state;
|
||||
hookData.open = open;
|
||||
hookData.close = close;
|
||||
hookData.toggle = toggle;
|
||||
return hookData;
|
||||
};
|
||||
|
||||
export default useToggleState
|
||||
export default useToggleState;
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import { isEqual, pick } from "lodash"
|
||||
import { isEqual, pick } from 'lodash';
|
||||
|
||||
export default function compareAddresses(address1: any, address2: any) {
|
||||
return isEqual(
|
||||
pick(address1, [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"address_1",
|
||||
"company",
|
||||
"postal_code",
|
||||
"city",
|
||||
"country_code",
|
||||
"province",
|
||||
"phone",
|
||||
'first_name',
|
||||
'last_name',
|
||||
'address_1',
|
||||
'company',
|
||||
'postal_code',
|
||||
'city',
|
||||
'country_code',
|
||||
'province',
|
||||
'phone',
|
||||
]),
|
||||
pick(address2, [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"address_1",
|
||||
"company",
|
||||
"postal_code",
|
||||
"city",
|
||||
"country_code",
|
||||
"province",
|
||||
"phone",
|
||||
])
|
||||
)
|
||||
'first_name',
|
||||
'last_name',
|
||||
'address_1',
|
||||
'company',
|
||||
'postal_code',
|
||||
'city',
|
||||
'country_code',
|
||||
'province',
|
||||
'phone',
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export const getBaseURL = () => {
|
||||
return process.env.NEXT_PUBLIC_BASE_URL || "https://localhost:8000"
|
||||
}
|
||||
return process.env.NEXT_PUBLIC_BASE_URL || 'https://localhost:8000';
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const getPercentageDiff = (original: number, calculated: number) => {
|
||||
const diff = original - calculated
|
||||
const decrease = (diff / original) * 100
|
||||
const diff = original - calculated;
|
||||
const decrease = (diff / original) * 100;
|
||||
|
||||
return decrease.toFixed()
|
||||
}
|
||||
return decrease.toFixed();
|
||||
};
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { getPercentageDiff } from "./get-precentage-diff"
|
||||
import { convertToLocale } from "./money"
|
||||
import { HttpTypes } from '@medusajs/types';
|
||||
|
||||
import { getPercentageDiff } from './get-precentage-diff';
|
||||
import { convertToLocale } from './money';
|
||||
|
||||
export const getPricesForVariant = (variant: any) => {
|
||||
if (!variant?.calculated_price?.calculated_amount) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -22,25 +23,25 @@ export const getPricesForVariant = (variant: any) => {
|
||||
price_type: variant.calculated_price.calculated_price.price_list_type,
|
||||
percentage_diff: getPercentageDiff(
|
||||
variant.calculated_price.original_amount,
|
||||
variant.calculated_price.calculated_amount
|
||||
variant.calculated_price.calculated_amount,
|
||||
),
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export function getProductPrice({
|
||||
product,
|
||||
variantId,
|
||||
}: {
|
||||
product: HttpTypes.StoreProduct
|
||||
variantId?: string
|
||||
product: HttpTypes.StoreProduct;
|
||||
variantId?: string;
|
||||
}) {
|
||||
if (!product || !product.id) {
|
||||
throw new Error("No product provided")
|
||||
throw new Error('No product provided');
|
||||
}
|
||||
|
||||
const cheapestPrice = () => {
|
||||
if (!product || !product.variants?.length) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
const cheapestVariant: any = product.variants
|
||||
@@ -49,31 +50,31 @@ export function getProductPrice({
|
||||
return (
|
||||
a.calculated_price.calculated_amount -
|
||||
b.calculated_price.calculated_amount
|
||||
)
|
||||
})[0]
|
||||
);
|
||||
})[0];
|
||||
|
||||
return getPricesForVariant(cheapestVariant)
|
||||
}
|
||||
return getPricesForVariant(cheapestVariant);
|
||||
};
|
||||
|
||||
const variantPrice = () => {
|
||||
if (!product || !variantId) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
const variant: any = product.variants?.find(
|
||||
(v) => v.id === variantId || v.sku === variantId
|
||||
)
|
||||
(v) => v.id === variantId || v.sku === variantId,
|
||||
);
|
||||
|
||||
if (!variant) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return getPricesForVariant(variant)
|
||||
}
|
||||
return getPricesForVariant(variant);
|
||||
};
|
||||
|
||||
return {
|
||||
product,
|
||||
cheapestPrice: cheapestPrice(),
|
||||
variantPrice: variantPrice(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export * from "./compare-addresses";
|
||||
export * from "./env";
|
||||
export * from "./get-precentage-diff";
|
||||
export * from "./get-product-price";
|
||||
export * from "./isEmpty";
|
||||
export * from "./medusa-error";
|
||||
export * from "./money";
|
||||
export * from "./product";
|
||||
export * from "./repeat";
|
||||
export * from "./sort-products";
|
||||
export * from './compare-addresses';
|
||||
export * from './env';
|
||||
export * from './get-precentage-diff';
|
||||
export * from './get-product-price';
|
||||
export * from './isEmpty';
|
||||
export * from './medusa-error';
|
||||
export * from './money';
|
||||
export * from './product';
|
||||
export * from './repeat';
|
||||
export * from './sort-products';
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export const isObject = (input: any) => input instanceof Object
|
||||
export const isArray = (input: any) => Array.isArray(input)
|
||||
export const isObject = (input: any) => input instanceof Object;
|
||||
export const isArray = (input: any) => Array.isArray(input);
|
||||
export const isEmpty = (input: any) => {
|
||||
return (
|
||||
input === null ||
|
||||
input === undefined ||
|
||||
(isObject(input) && Object.keys(input).length === 0) ||
|
||||
(isArray(input) && (input as any[]).length === 0) ||
|
||||
(typeof input === "string" && input.trim().length === 0)
|
||||
)
|
||||
}
|
||||
(typeof input === 'string' && input.trim().length === 0)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,21 +2,21 @@ export default function medusaError(error: any): never {
|
||||
if (error.response) {
|
||||
// The request was made and the server responded with a status code
|
||||
// that falls out of the range of 2xx
|
||||
const u = new URL(error.config.url, error.config.baseURL)
|
||||
console.error("Resource:", u.toString())
|
||||
console.error("Response data:", error.response.data)
|
||||
console.error("Status code:", error.response.status)
|
||||
console.error("Headers:", error.response.headers)
|
||||
const u = new URL(error.config.url, error.config.baseURL);
|
||||
console.error('Resource:', u.toString());
|
||||
console.error('Response data:', error.response.data);
|
||||
console.error('Status code:', error.response.status);
|
||||
console.error('Headers:', error.response.headers);
|
||||
|
||||
// Extracting the error message from the response data
|
||||
const message = error.response.data.message || error.response.data
|
||||
const message = error.response.data.message || error.response.data;
|
||||
|
||||
throw new Error(message.charAt(0).toUpperCase() + message.slice(1) + ".")
|
||||
throw new Error(message.charAt(0).toUpperCase() + message.slice(1) + '.');
|
||||
} else if (error.request) {
|
||||
// The request was made but no response was received
|
||||
throw new Error("No response received: " + error.request)
|
||||
throw new Error('No response received: ' + error.request);
|
||||
} else {
|
||||
// Something happened in setting up the request that triggered an Error
|
||||
throw new Error("Error setting up the request: " + error.message)
|
||||
throw new Error('Error setting up the request: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user