Merge pull request #77 from MR-medreport/develop

develop -> main
This commit is contained in:
2025-09-06 19:59:39 +00:00
committed by GitHub
10 changed files with 152 additions and 92 deletions

View File

@@ -1,6 +1,7 @@
"use client" "use client"
import { Badge, Heading, Text } from "@medusajs/ui" import { Badge, Text } from "@medusajs/ui"
import { toast } from '@kit/ui/sonner';
import React, { useActionState } from "react"; import React, { useActionState } from "react";
import { applyPromotions, submitPromotionForm } from "@lib/data/cart" import { applyPromotions, submitPromotionForm } from "@lib/data/cart"
@@ -31,11 +32,19 @@ export default function DiscountCode({ cart }: {
const removePromotionCode = async (code: string) => { const removePromotionCode = async (code: string) => {
const validPromotions = promotions.filter( const validPromotions = promotions.filter(
(promotion) => promotion.code !== code (promotion) => promotion.code !== code,
) )
await applyPromotions( await applyPromotions(
validPromotions.filter((p) => p.code === undefined).map((p) => p.code!) validPromotions.filter((p) => p.code === undefined).map((p) => p.code!),
{
onSuccess: () => {
toast.success(t('cart:discountCode.removeSuccess'));
},
onError: () => {
toast.error(t('cart:discountCode.removeError'));
},
}
) )
} }
@@ -45,7 +54,14 @@ export default function DiscountCode({ cart }: {
.map((p) => p.code!) .map((p) => p.code!)
codes.push(code.toString()) codes.push(code.toString())
await applyPromotions(codes) await applyPromotions(codes, {
onSuccess: () => {
toast.success(t('cart:discountCode.addSuccess'));
},
onError: () => {
toast.error(t('cart:discountCode.addError'));
},
});
form.reset() form.reset()
} }
@@ -64,7 +80,7 @@ export default function DiscountCode({ cart }: {
<Form {...form}> <Form {...form}>
<form <form
onSubmit={form.handleSubmit((data) => addPromotionCode(data.code))} onSubmit={form.handleSubmit((data) => addPromotionCode(data.code))}
className="w-full mb-2 flex gap-x-2" className="w-full mb-2 flex gap-x-2 sm:flex-row flex-col gap-y-2"
> >
<FormField <FormField
name={'code'} name={'code'}
@@ -87,17 +103,13 @@ export default function DiscountCode({ cart }: {
</form> </form>
</Form> </Form>
<p className="text-sm text-muted-foreground"> {promotions.length > 0 ? (
<Trans i18nKey={'cart:discountCode.subtitle'} /> <div className="w-full flex items-center mt-4">
<div className="flex flex-col w-full gap-y-2">
<p>
<Trans i18nKey={'cart:discountCode.appliedCodes'} />
</p> </p>
{promotions.length > 0 && (
<div className="w-full flex items-center">
<div className="flex flex-col w-full">
<Heading className="txt-medium mb-2">
Promotion(s) applied:
</Heading>
{promotions.map((promotion) => { {promotions.map((promotion) => {
return ( return (
<div <div
@@ -110,6 +122,7 @@ export default function DiscountCode({ cart }: {
<Badge <Badge
color={promotion.is_automatic ? "green" : "grey"} color={promotion.is_automatic ? "green" : "grey"}
size="small" size="small"
className="px-4"
> >
{promotion.code} {promotion.code}
</Badge>{" "} </Badge>{" "}
@@ -151,7 +164,7 @@ export default function DiscountCode({ cart }: {
> >
<Trash size={14} /> <Trash size={14} />
<span className="sr-only"> <span className="sr-only">
Remove discount code from order <Trans i18nKey={'cart:discountCode.remove'} />
</span> </span>
</button> </button>
)} )}
@@ -160,6 +173,10 @@ export default function DiscountCode({ cart }: {
})} })}
</div> </div>
</div> </div>
) : (
<p className="text-sm text-muted-foreground">
<Trans i18nKey={'cart:discountCode.subtitle'} />
</p>
)} )}
</div> </div>
) )

View File

@@ -18,7 +18,7 @@ import { useTranslation } from "react-i18next";
import { handleNavigateToPayment } from "@/lib/services/medusaCart.service"; import { handleNavigateToPayment } from "@/lib/services/medusaCart.service";
import AnalysisLocation from "./analysis-location"; import AnalysisLocation from "./analysis-location";
const IS_DISCOUNT_SHOWN = false as boolean; const IS_DISCOUNT_SHOWN = true as boolean;
export default function Cart({ export default function Cart({
cart, cart,
@@ -77,7 +77,40 @@ export default function Cart({
<CartItems cart={cart} items={ttoServiceItems} productColumnLabelKey="cart:items.ttoServices.productColumnLabel" /> <CartItems cart={cart} items={ttoServiceItems} productColumnLabelKey="cart:items.ttoServices.productColumnLabel" />
</div> </div>
{hasCartItems && ( {hasCartItems && (
<div className="flex justify-end gap-x-4 px-6 py-4"> <>
<div className="flex justify-end gap-x-4 px-6 pt-4">
<div className="mr-[36px]">
<p className="ml-0 font-bold text-sm text-muted-foreground">
<Trans i18nKey="cart:subtotal" />
</p>
</div>
<div className="mr-[116px]">
<p className="text-sm">
{formatCurrency({
value: cart.subtotal,
currencyCode: cart.currency_code,
locale: language,
})}
</p>
</div>
</div>
<div className="flex justify-end gap-x-4 px-6 py-2">
<div className="mr-[36px]">
<p className="ml-0 font-bold text-sm text-muted-foreground">
<Trans i18nKey="cart:promotionsTotal" />
</p>
</div>
<div className="mr-[116px]">
<p className="text-sm">
{formatCurrency({
value: cart.discount_total,
currencyCode: cart.currency_code,
locale: language,
})}
</p>
</div>
</div>
<div className="flex justify-end gap-x-4 px-6">
<div className="mr-[36px]"> <div className="mr-[36px]">
<p className="ml-0 font-bold text-sm"> <p className="ml-0 font-bold text-sm">
<Trans i18nKey="cart:total" /> <Trans i18nKey="cart:total" />
@@ -93,12 +126,13 @@ export default function Cart({
</p> </p>
</div> </div>
</div> </div>
</>
)} )}
<div className="flex gap-y-6 py-8"> <div className="flex sm:flex-row flex-col gap-y-6 py-8 gap-x-4">
{IS_DISCOUNT_SHOWN && ( {IS_DISCOUNT_SHOWN && (
<Card <Card
className="flex flex-col justify-between w-1/2" className="flex flex-col justify-between w-full sm:w-1/2"
> >
<CardHeader className="pb-4"> <CardHeader className="pb-4">
<h5> <h5>
@@ -113,7 +147,7 @@ export default function Cart({
{isLocationsShown && ( {isLocationsShown && (
<Card <Card
className="flex flex-col justify-between w-1/2" className="flex flex-col justify-between w-full sm:w-1/2"
> >
<CardHeader className="pb-4"> <CardHeader className="pb-4">
<h5> <h5>

View File

@@ -10,6 +10,7 @@ import {
getClientInstitution, getClientInstitution,
getClientPerson, getClientPerson,
getConfidentiality, getConfidentiality,
getOrderEnteredPerson,
getPais, getPais,
getPatient, getPatient,
getProviderInstitution, getProviderInstitution,
@@ -553,12 +554,10 @@ export async function composeOrderXML({
${getPais(USER, RECIPIENT, orderCreatedAt, orderId)} ${getPais(USER, RECIPIENT, orderCreatedAt, orderId)}
<Tellimus cito="EI"> <Tellimus cito="EI">
<ValisTellimuseId>${orderId}</ValisTellimuseId> <ValisTellimuseId>${orderId}</ValisTellimuseId>
<!--<TellijaAsutus>-->
${getClientInstitution()} ${getClientInstitution()}
<!--<TeostajaAsutus>-->
${getProviderInstitution()} ${getProviderInstitution()}
<!--<TellijaIsik>--> ${getClientPerson()}
${getClientPerson(person)} ${getOrderEnteredPerson()}
<TellijaMarkused>${comment ?? ''}</TellijaMarkused> <TellijaMarkused>${comment ?? ''}</TellijaMarkused>
${getPatient(person)} ${getPatient(person)}
${getConfidentiality()} ${getConfidentiality()}

View File

@@ -3,6 +3,7 @@
import { import {
getClientInstitution, getClientInstitution,
getClientPerson, getClientPerson,
getOrderEnteredPerson,
getPais, getPais,
getPatient, getPatient,
getProviderInstitution, getProviderInstitution,
@@ -104,7 +105,8 @@ export async function composeOrderTestResponseXML({
<ValisTellimuseId>${orderId}</ValisTellimuseId> <ValisTellimuseId>${orderId}</ValisTellimuseId>
${getClientInstitution({ index: 1 })} ${getClientInstitution({ index: 1 })}
${getProviderInstitution({ index: 1 })} ${getProviderInstitution({ index: 1 })}
${getClientPerson(person)} ${getClientPerson()}
${getOrderEnteredPerson()}
<TellijaMarkused>Siia tuleb tellija poolne märkus</TellijaMarkused> <TellijaMarkused>Siia tuleb tellija poolne märkus</TellijaMarkused>
${getPatient(person)} ${getPatient(person)}

View File

@@ -21,70 +21,48 @@ export const getPais = (
<Saaja>${recipient}</Saaja> <Saaja>${recipient}</Saaja>
<Aeg>${format(createdAt, DATE_TIME_FORMAT)}</Aeg> <Aeg>${format(createdAt, DATE_TIME_FORMAT)}</Aeg>
<SaadetisId>${orderId}</SaadetisId> <SaadetisId>${orderId}</SaadetisId>
<Email>argo@medreport.ee</Email> <Email>info@medreport.ee</Email>
</Pais>`; </Pais>`;
}; };
export const getClientInstitution = ({ index }: { index?: number } = {}) => { export const getClientInstitution = ({ index }: { index?: number } = {}) => {
if (isProd) {
// return correct data
}
return `<Asutus tyyp="TELLIJA" ${index ? ` jarjenumber="${index}"` : ''}> return `<Asutus tyyp="TELLIJA" ${index ? ` jarjenumber="${index}"` : ''}>
<AsutuseId>16381793</AsutuseId> <AsutuseId>16381793</AsutuseId>
<AsutuseNimi>MedReport OÜ</AsutuseNimi> <AsutuseNimi>MedReport OÜ</AsutuseNimi>
<AsutuseKood>TSU</AsutuseKood> <AsutuseKood>MRP</AsutuseKood>
<Telefon>+37258871517</Telefon> <Telefon>+37258871517</Telefon>
</Asutus>`; </Asutus>`;
}; };
export const getProviderInstitution = ({ index }: { index?: number } = {}) => { export const getProviderInstitution = ({ index }: { index?: number } = {}) => {
if (isProd) {
// return correct data
}
return `<Asutus tyyp="TEOSTAJA" ${index ? ` jarjenumber="${index}"` : ''}> return `<Asutus tyyp="TEOSTAJA" ${index ? ` jarjenumber="${index}"` : ''}>
<AsutuseId>11107913</AsutuseId> <AsutuseId>11107913</AsutuseId>
<AsutuseNimi>Synlab HTI Tallinn</AsutuseNimi> <AsutuseNimi>Synlab Eesti OÜ</AsutuseNimi>
<AsutuseKood>SLA</AsutuseKood> <AsutuseKood>HTI</AsutuseKood>
<AllyksuseNimi>Synlab HTI Tallinn</AllyksuseNimi> <AllyksuseNimi>Synlab HTI Tallinn</AllyksuseNimi>
<Telefon>+3723417123</Telefon> <Telefon>+37217123</Telefon>
</Asutus>`; </Asutus>`;
}; };
export const getClientPerson = ({ export const getClientPerson = () => {
idCode,
firstName,
lastName,
phone,
}: {
idCode: string,
firstName: string,
lastName: string,
phone: string,
}) => {
if (isProd) {
// return correct data
}
return `<Personal tyyp="TELLIJA" jarjenumber="1"> return `<Personal tyyp="TELLIJA" jarjenumber="1">
<PersonalOID>1.3.6.1.4.1.28284.6.2.4.9</PersonalOID> <PersonalOID>1.3.6.1.4.1.28284.6.2.4.9</PersonalOID>
<PersonalKood>${idCode}</PersonalKood> <PersonalKood>D07907</PersonalKood>
<PersonalPerekonnaNimi>${lastName}</PersonalPerekonnaNimi> <PersonalPerekonnaNimi>Eduard</PersonalPerekonnaNimi>
<PersonalEesNimi>${firstName}</PersonalEesNimi> <PersonalEesNimi>Tsvetkov</PersonalEesNimi>
${phone ? `<Telefon>${phone.startsWith('+372') ? phone : `+372${phone}`}</Telefon>` : ''} <Telefon>+37258131202</Telefon>
</Personal>`; </Personal>`;
}; };
// export const getOrderEnteredPerson = () => { export const getOrderEnteredPerson = () => {
// if (isProd) { return `<Personal tyyp="SISESTAJA" jarjenumber="2">
// // return correct data <PersonalOID>1.3.6.1.4.1.28284.6.2.4.9</PersonalOID>
// } <PersonalKood>D07907</PersonalKood>
// return `<Personal tyyp="SISESTAJA" jarjenumber="1"> <PersonalPerekonnaNimi>Eduard</PersonalPerekonnaNimi>
// <PersonalOID>1.3.6.1.4.1.28284.6.2.4.9</PersonalOID> <PersonalEesNimi>Tsvetkov</PersonalEesNimi>
// <PersonalKood>D07907</PersonalKood> <Telefon>+37258131202</Telefon>
// <PersonalPerekonnaNimi>Eduard</PersonalPerekonnaNimi> </Personal>`;
// <PersonalEesNimi>Tsvetkov</PersonalEesNimi> };
// <Telefon>+37258131202</Telefon>
// </Personal>`;
// };
export const getPatient = ({ export const getPatient = ({
idCode, idCode,

View File

@@ -87,7 +87,10 @@ export async function getOrSetCart(countryCode: string) {
return cart; return cart;
} }
export async function updateCart({ id, ...data }: HttpTypes.StoreUpdateCart & { id?: string }) { export async function updateCart(
{ id, ...data }: HttpTypes.StoreUpdateCart & { id?: string },
{ onSuccess, onError }: { onSuccess: () => void, onError: () => void } = { onSuccess: () => {}, onError: () => {} },
) {
const cartId = id || (await getCartId()); const cartId = id || (await getCartId());
if (!cartId) { if (!cartId) {
@@ -109,9 +112,13 @@ export async function updateCart({ id, ...data }: HttpTypes.StoreUpdateCart & {
const fulfillmentCacheTag = await getCacheTag("fulfillment"); const fulfillmentCacheTag = await getCacheTag("fulfillment");
revalidateTag(fulfillmentCacheTag); revalidateTag(fulfillmentCacheTag);
onSuccess();
return cart; return cart;
}) })
.catch(medusaError); .catch((e) => {
onError();
return medusaError(e);
});
} }
export async function addToCart({ export async function addToCart({
@@ -259,7 +266,10 @@ export async function initiatePaymentSession(
.catch(medusaError); .catch(medusaError);
} }
export async function applyPromotions(codes: string[]) { export async function applyPromotions(
codes: string[],
{ onSuccess, onError }: { onSuccess: () => void, onError: () => void } = { onSuccess: () => {}, onError: () => {} },
) {
const cartId = await getCartId(); const cartId = await getCartId();
if (!cartId) { if (!cartId) {
@@ -278,8 +288,13 @@ export async function applyPromotions(codes: string[]) {
const fulfillmentCacheTag = await getCacheTag("fulfillment"); const fulfillmentCacheTag = await getCacheTag("fulfillment");
revalidateTag(fulfillmentCacheTag); revalidateTag(fulfillmentCacheTag);
onSuccess();
}) })
.catch(medusaError); .catch((e) => {
onError();
return medusaError(e);
});
} }
export async function applyGiftCard(code: string) { export async function applyGiftCard(code: string) {

View File

@@ -127,7 +127,7 @@ export async function login(_currentState: unknown, formData: FormData) {
} }
} }
export async function signout(countryCode: string) { export async function signout(countryCode?: string, shouldRedirect = true) {
await sdk.auth.logout() await sdk.auth.logout()
await removeAuthToken() await removeAuthToken()
@@ -140,7 +140,9 @@ export async function signout(countryCode: string) {
const cartCacheTag = await getCacheTag("carts") const cartCacheTag = await getCacheTag("carts")
revalidateTag(cartCacheTag) revalidateTag(cartCacheTag)
redirect(`/${countryCode}/account`) if (shouldRedirect) {
redirect(`/${countryCode!}/account`)
}
} }
export async function transferCart() { export async function transferCart() {

View File

@@ -1,12 +1,14 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import { useSupabase } from './use-supabase'; import { useSupabase } from './use-supabase';
import { signout } from '../../../features/medusa-storefront/src/lib/data/customer';
export function useSignOut() { export function useSignOut() {
const client = useSupabase(); const client = useSupabase();
return useMutation({ return useMutation({
mutationFn: () => { mutationFn: async () => {
await signout(undefined, false);
return client.auth.signOut(); return client.auth.signOut();
}, },
}); });

View File

@@ -5,6 +5,7 @@
"emptyCartMessageDescription": "Add items to your cart to continue.", "emptyCartMessageDescription": "Add items to your cart to continue.",
"subtotal": "Subtotal", "subtotal": "Subtotal",
"total": "Total", "total": "Total",
"promotionsTotal": "Promotions total",
"table": { "table": {
"item": "Item", "item": "Item",
"quantity": "Quantity", "quantity": "Quantity",
@@ -24,10 +25,13 @@
"timeoutAction": "Continue" "timeoutAction": "Continue"
}, },
"discountCode": { "discountCode": {
"title": "Gift card or promotion code",
"label": "Add Promotion Code(s)", "label": "Add Promotion Code(s)",
"apply": "Apply", "apply": "Apply",
"subtitle": "If you wish, you can add a promotion code", "subtitle": "If you wish, you can add a promotion code",
"placeholder": "Enter promotion code" "placeholder": "Enter promotion code",
"remove": "Remove promotion code",
"appliedCodes": "Promotion(s) applied:"
}, },
"items": { "items": {
"synlabAnalyses": { "synlabAnalyses": {

View File

@@ -4,6 +4,7 @@
"emptyCartMessage": "Sinu ostukorv on tühi", "emptyCartMessage": "Sinu ostukorv on tühi",
"emptyCartMessageDescription": "Lisa tooteid ostukorvi, et jätkata.", "emptyCartMessageDescription": "Lisa tooteid ostukorvi, et jätkata.",
"subtotal": "Vahesumma", "subtotal": "Vahesumma",
"promotionsTotal": "Soodustuse summa",
"total": "Summa", "total": "Summa",
"table": { "table": {
"item": "Toode", "item": "Toode",
@@ -28,7 +29,13 @@
"label": "Lisa promo kood", "label": "Lisa promo kood",
"apply": "Rakenda", "apply": "Rakenda",
"subtitle": "Kui soovid, võid lisada promo koodi", "subtitle": "Kui soovid, võid lisada promo koodi",
"placeholder": "Sisesta promo kood" "placeholder": "Sisesta promo kood",
"remove": "Eemalda promo kood",
"appliedCodes": "Rakendatud sooduskoodid:",
"removeError": "Sooduskoodi eemaldamine ebaõnnestus",
"removeSuccess": "Sooduskood eemaldatud",
"addError": "Sooduskoodi rakendamine ebaõnnestus",
"addSuccess": "Sooduskood rakendatud"
}, },
"items": { "items": {
"synlabAnalyses": { "synlabAnalyses": {