@@ -251,20 +255,21 @@ function TreatmentTable({
treatmentOrder: CustomerOrder;
lineItems: OrderLineItemFullFragment[];
}) {
+ const {t} = useTranslation(['account'], {keyPrefix: 'orders.id'});
if (treatmentOrder.line_items.length === 0) return null;
return (
<>
- Behandlinger
+ {t('treatments')}
- Billed:
- Detaljer:
- Total
+ {t('image')}:
+ {t('details')}:
+ {t('total')}
@@ -295,9 +300,11 @@ function TreatmentLineRow({
treatmentLineItem: CustomerOrderLineItem;
lineItem: OrderLineItemFullFragment;
}) {
+ const {format} = useDate();
+ const {t} = useTranslation(['account'], {keyPrefix: 'orders.id'});
return (
-
+
{lineItem?.image && (
@@ -309,36 +316,36 @@ function TreatmentLineRow({
{treatmentLineItem.title}
{treatmentLineItem.user ? (
-
- Hos: {' '}
-
- {treatmentLineItem.user?.fullname}
-
-
+
+ {treatmentLineItem.user.fullname}
+ ,
+ ]}
+ />
) : (
-
- Hos: Slettet skønhedsekspert
-
+ t('visiting_deleted')
)}
- Tid: {' '}
+ {t('time')}: {' '}
{format(
new Date(treatmentLineItem.properties.from || ''),
"EEEE 'd.' d'.' LLL 'kl 'HH:mm",
- {
- locale: da,
- },
)}
{treatmentLineItem.shipping ? (
- Location: {' '}
+ {t('location')}: {' '}
{treatmentLineItem.shipping.destination.fullAddress}
- Udgifterne bliver beregnet under købsprocessen.
+ {t('location_expenses')}
{treatmentLineItem.shipping.cost.value}{' '}
{treatmentLineItem.shipping.cost.currency}
@@ -346,7 +353,7 @@ function TreatmentLineRow({
) : (
<>
- Location: {' '}
+ {t('location')}: {' '}
{treatmentLineItem.location?.fullAddress}
>
diff --git a/app/routes/account.orders._index.tsx b/app/routes/account.orders._index.tsx
index 10970503..cd72439e 100644
--- a/app/routes/account.orders._index.tsx
+++ b/app/routes/account.orders._index.tsx
@@ -1,10 +1,10 @@
-import {Button, Card, Flex, Table, Title} from '@mantine/core';
+import {Button, Card, Container, Flex, rem, Table, Title} from '@mantine/core';
import {Link, useLoaderData, type MetaFunction} from '@remix-run/react';
import {
- Money,
- Pagination,
flattenConnection,
getPaginationVariables,
+ Money,
+ Pagination,
} from '@shopify/hydrogen';
import {json, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
import {IconHeartHandshake} from '@tabler/icons-react';
@@ -12,11 +12,11 @@ import type {
CustomerOrdersFragment,
OrderItemFragment,
} from 'customer-accountapi.generated';
-import {format} from 'date-fns';
-import {da} from 'date-fns/locale';
+import {useTranslation} from 'react-i18next';
import {AccountContent} from '~/components/account/AccountContent';
import {AccountTitle} from '~/components/account/AccountTitle';
import {CUSTOMER_ORDERS_QUERY} from '~/graphql/customer-account/CustomerOrdersQuery';
+import {useDate} from '~/lib/duration';
export const meta: MetaFunction = () => {
return [{title: 'Købshistorik'}];
@@ -51,26 +51,22 @@ export async function loader({request, context}: LoaderFunctionArgs) {
}
export default function Orders() {
+ const {t} = useTranslation(['account'], {keyPrefix: 'orders'});
const {customer} = useLoaderData<{customer: CustomerOrdersFragment}>();
const {orders} = customer;
return (
- <>
-
- Orders ({orders.nodes.length})
- >
- }
- />
+
+
- >
+
);
}
function OrdersTable({orders}: Pick) {
+ const {t} = useTranslation(['account', 'global'], {keyPrefix: 'orders'});
return orders?.nodes.length ? (
{({nodes, isLoading, PreviousLink, NextLink}) => {
@@ -78,16 +74,16 @@ function OrdersTable({orders}: Pick) {
<>
- ↑ Hent tidligere
+ ↑ {t('global:pagination_previous_button')}
- Dato
- Betaling
- Status
- Beløb
+ {t('date')}
+ {t('payment')}
+ {t('status')}
+ {t('total')}
@@ -101,7 +97,7 @@ function OrdersTable({orders}: Pick) {
- Hent flere ↓
+ {t('global:pagination_next_button')} ↓
>
@@ -114,15 +110,16 @@ function OrdersTable({orders}: Pick) {
}
function EmptyOrders() {
+ const {t} = useTranslation(['account', 'global'], {keyPrefix: 'orders'});
return (
- Du har ikke afgivet nogen ordre endnu
+ {t('empty')}
- Gå til forside →
+ {t('goto_frontpage')} →
@@ -130,12 +127,11 @@ function EmptyOrders() {
}
function OrderItem({order}: {order: OrderItemFragment}) {
+ const {format} = useDate();
const fulfillmentStatus = flattenConnection(order.fulfillments)[0]?.status;
return (
-
- {format(new Date(order.processedAt), 'PPPP', {locale: da})}
-
+ {format(new Date(order.processedAt), 'PPPP')}
{order.financialStatus}
{fulfillmentStatus && {fulfillmentStatus}
}
diff --git a/app/routes/account.profile.tsx b/app/routes/account.profile.tsx
index 3412792c..83e4103b 100644
--- a/app/routes/account.profile.tsx
+++ b/app/routes/account.profile.tsx
@@ -1,4 +1,4 @@
-import {Blockquote, Stack, TextInput} from '@mantine/core';
+import {Blockquote, Container, rem, Stack, TextInput} from '@mantine/core';
import {
Form,
useActionData,
@@ -12,6 +12,7 @@ import {
type LoaderFunctionArgs,
} from '@shopify/remix-oxygen';
import type {CustomerFragment} from 'customer-accountapi.generated';
+import {useTranslation} from 'react-i18next';
import {AccountContent} from '~/components/account/AccountContent';
import {AccountTitle} from '~/components/account/AccountTitle';
import {SubmitButton} from '~/components/form/SubmitButton';
@@ -71,7 +72,7 @@ export async function action({request, context}: ActionFunctionArgs) {
}
if (!data?.customerUpdate?.customer) {
- throw new Error('Customer profile update failed.');
+ throw new Error(data?.customerUpdate?.userErrors[0].message);
}
return json(
@@ -99,18 +100,19 @@ export async function action({request, context}: ActionFunctionArgs) {
}
export default function AccountProfile() {
+ const {t} = useTranslation(['account'], {keyPrefix: 'profile'});
const account = useOutletContext<{customer: CustomerFragment}>();
const action = useActionData();
const customer = action?.customer ?? account?.customer;
return (
- <>
-
+
+
{action?.error ? (
- Fejl:
+ {t('error')}:
{action.error}
@@ -119,26 +121,24 @@ export default function AccountProfile() {
- >
+
);
}
diff --git a/app/routes/account.tsx b/app/routes/account.tsx
index 4c9970d5..bd6f763f 100644
--- a/app/routes/account.tsx
+++ b/app/routes/account.tsx
@@ -1,40 +1,25 @@
-import {AppShell, Flex, Text, UnstyledButton} from '@mantine/core';
-import {useDisclosure, useMediaQuery} from '@mantine/hooks';
import tiptapStyles from '@mantine/tiptap/styles.css?url';
import {
- Link,
Outlet,
type ShouldRevalidateFunction,
useLoaderData,
} from '@remix-run/react';
-import {parseGid} from '@shopify/hydrogen';
-import {
- json,
- type LoaderFunctionArgs,
- type SerializeFrom,
-} from '@shopify/remix-oxygen';
-import {
- IconAddressBook,
- IconCalendarEvent,
- IconClock,
- IconHome,
- IconLocation,
- IconMenu2,
- IconShoppingBag,
- IconUser,
-} from '@tabler/icons-react';
+import {json, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
import {type CustomerFragment} from 'customer-accountapi.generated';
import {useEffect} from 'react';
import notify, {Toaster} from 'react-hot-toast';
import {getToast} from 'remix-toast';
-import {AccountMenu} from '~/components/AccountMenu';
import {CUSTOMER_DETAILS_QUERY} from '~/graphql/customer-account/CustomerDetailsQuery';
-import {getBookingShopifyApi} from '~/lib/api/bookingShopifyApi';
import {type User} from '~/lib/api/model';
export function links() {
return [{rel: 'stylesheet', href: tiptapStyles}];
}
+
+export const handle: Handle = {
+ i18n: ['global', 'account', 'professions'],
+};
+
export type AccountOutlet = {
customer: CustomerFragment;
user?: User | null;
@@ -67,25 +52,11 @@ export async function loader({context, request}: LoaderFunctionArgs) {
throw new Error('Customer not found');
}
- const {payload: userIsBusiness} =
- await getBookingShopifyApi().customerIsBusiness(
- parseGid(data.customer.id).id,
- );
-
- let user = undefined;
- if (userIsBusiness.isBusiness) {
- user = (
- await getBookingShopifyApi().customerGet(parseGid(data.customer.id).id)
- ).payload;
- }
-
const {toast} = await getToast(request);
return json(
{
customer: data.customer,
- isBusiness: userIsBusiness.isBusiness,
- user,
toast,
},
{
@@ -98,7 +69,7 @@ export async function loader({context, request}: LoaderFunctionArgs) {
}
export default function Acccount() {
- const {customer, user, isBusiness, toast} = useLoaderData();
+ const {customer, toast} = useLoaderData();
useEffect(() => {
if (toast) {
@@ -117,184 +88,13 @@ export default function Acccount() {
}, [toast]);
return (
-
- {' '}
+ <>
+
-
-
- );
-}
-
-function AccountLayout({
- children,
- ...props
-}: {
- children: React.ReactNode;
-} & Awaited>) {
- const [opened, {toggle, close}] = useDisclosure(false);
- const isMobile = useMediaQuery('(max-width: 48em)');
-
- return (
-
-
-
-
-
- {children}
-
-
-
- {props.user ? (
- <>
-
-
-
- Lokationer
-
-
-
-
-
- Vagtplan
-
-
-
-
-
- Ydelser
-
-
-
-
-
- Kalendar
-
-
- >
- ) : (
- <>
-
-
-
- Hjem
-
-
-
-
-
- Købshistorik
-
-
-
-
-
- Konto
-
-
-
-
-
- Adresser
-
-
- >
- )}
-
-
-
- Menu
-
-
-
-
-
+ >
);
}
diff --git a/app/routes/account_._index.tsx b/app/routes/account_._index.tsx
deleted file mode 100644
index 28b2c9cf..00000000
--- a/app/routes/account_._index.tsx
+++ /dev/null
@@ -1,201 +0,0 @@
-import {
- BackgroundImage,
- Blockquote,
- Button,
- Flex,
- Paper,
- rem,
- Stack,
- Text,
- TextInput,
- Title,
-} from '@mantine/core';
-import {
- Form,
- useActionData,
- useLoaderData,
- useNavigation,
- type MetaFunction,
-} from '@remix-run/react';
-import type {CustomerUpdateInput} from '@shopify/hydrogen/customer-account-api-types';
-import {
- json,
- redirect,
- type ActionFunctionArgs,
- type LoaderFunctionArgs,
-} from '@shopify/remix-oxygen';
-import type {CustomerFragment} from 'customer-accountapi.generated';
-import {CUSTOMER_DETAILS_QUERY} from '~/graphql/customer-account/CustomerDetailsQuery';
-import {CUSTOMER_UPDATE_MUTATION} from '~/graphql/customer-account/CustomerUpdateMutation';
-
-export type ActionResponse = {
- error: string | null;
- customer: CustomerFragment | null;
-};
-
-export const meta: MetaFunction = () => {
- return [{title: 'Profile'}];
-};
-
-export async function loader({context}: LoaderFunctionArgs) {
- await context.customerAccount.handleAuthStatus();
-
- const {data, errors} = await context.customerAccount.query(
- CUSTOMER_DETAILS_QUERY,
- );
-
- if (errors?.length || !data?.customer) {
- throw new Error('Customer not found');
- }
-
- if (data.customer.firstName && data.customer.lastName) {
- return redirect('/account/dashboard');
- }
-
- return json(data, {
- headers: {
- 'Set-Cookie': await context.session.commit(),
- },
- });
-}
-
-export async function action({request, context}: ActionFunctionArgs) {
- const {customerAccount} = context;
-
- const form = await request.formData();
-
- try {
- const customer: CustomerUpdateInput = {};
- const validInputKeys = ['firstName', 'lastName'] as const;
- for (const [key, value] of form.entries()) {
- if (!validInputKeys.includes(key as any)) {
- continue;
- }
- if (typeof value === 'string' && value.length) {
- customer[key as (typeof validInputKeys)[number]] = value;
- }
- }
-
- // update customer and possibly password
- const {data, errors} = await customerAccount.mutate(
- CUSTOMER_UPDATE_MUTATION,
- {
- variables: {
- customer,
- },
- },
- );
-
- if (errors?.length) {
- throw new Error(errors[0].message);
- }
-
- if (!data?.customerUpdate?.customer) {
- throw new Error('Customer profile update failed.');
- }
-
- return json(
- {
- error: null,
- customer: data?.customerUpdate?.customer,
- },
- {
- headers: {
- 'Set-Cookie': await context.session.commit(),
- },
- },
- );
- } catch (error: any) {
- return json(
- {error: error.message, customer: null},
- {
- status: 400,
- headers: {
- 'Set-Cookie': await context.session.commit(),
- },
- },
- );
- }
-}
-
-export default function AccountProfile() {
- const loader = useLoaderData<{customer: CustomerFragment}>();
- const {state} = useNavigation();
- const action = useActionData();
- const customer = action?.customer ?? loader?.customer;
-
- return (
-
-
-
-
- Velkommen til vores platform
-
-
-
- For at gøre din oplevelse hos os mere personlig og effektiv, bedes
- du venligst oplyse dit fornavn og efternavn.{' '}
-
-
- {action?.error ? (
-
- Fejl:
-
- {action.error}
-
- ) : null}
-
-
-
-
-
-
- Gem og fortsæt
-
-
-
-
-
- );
-}
diff --git a/app/routes/account_.authorize.tsx b/app/routes/account_.authorize.tsx
index f7a8723e..05a04f54 100644
--- a/app/routes/account_.authorize.tsx
+++ b/app/routes/account_.authorize.tsx
@@ -1,5 +1,6 @@
import type {LoaderFunctionArgs} from '@shopify/remix-oxygen';
export async function loader({context}: LoaderFunctionArgs) {
+ console.log('called this before redirect');
return context.customerAccount.authorize();
}
diff --git a/app/routes/business._index.tsx b/app/routes/business._index.tsx
new file mode 100644
index 00000000..f1dc4d5d
--- /dev/null
+++ b/app/routes/business._index.tsx
@@ -0,0 +1,237 @@
+import {
+ Avatar,
+ Button,
+ Card,
+ Container,
+ Divider,
+ Flex,
+ Grid,
+ Group,
+ rem,
+ Stack,
+ Text,
+ Title,
+} from '@mantine/core';
+import {Form, Link, useLoaderData, useOutletContext} from '@remix-run/react';
+import {json, type LoaderFunctionArgs} from '@remix-run/server-runtime';
+import {
+ IconBook,
+ IconClock,
+ IconCurrencyDollar,
+ IconGps,
+ IconHeart,
+ IconLogout,
+ IconParachute,
+ IconPlane,
+ IconShoppingBag,
+} from '@tabler/icons-react';
+import {AccountMenuLink} from '~/components/account/AccountMenuLink';
+import {useMobile} from '~/hooks/isMobile';
+import {getBookingShopifyApi} from '~/lib/api/bookingShopifyApi';
+import {getCustomer} from '~/lib/get-customer';
+import {modifyImageUrl} from '~/lib/image';
+import {type AccountOutlet} from './account';
+
+export async function loader({context}: LoaderFunctionArgs) {
+ const customerId = await getCustomer({context});
+
+ const status = await getBookingShopifyApi().customerStatus(customerId);
+
+ return json({
+ status: status.payload,
+ });
+}
+
+export default function AccountIndex() {
+ const {status} = useLoaderData();
+ const {customer, user} = useOutletContext();
+ const isMobile = useMobile();
+
+ return (
+
+
+
+
+
+ {user?.images?.profile?.url ? (
+
+ ) : (
+
+ )}
+
+
+ {customer.firstName} {customer.lastName}
+
+
+ {customer.emailAddress?.emailAddress}
+
+
+
+
+
+
+ {customer.tags.includes('business') ? (
+
+
+
+
+
+ Konto
+
+ Din personlig konto
+
+
+ Gå tilbage til konto
+
+
+
+ ) : null}
+
+
+
+
+
+
+ Profil
+
+ Opdater dine personlige oplysninger
+
+
+
+
+
+
+
+
+ Lokationer
+
+ Administrer dine lokationer
+
+
+
+
+
+
+
+
+ Vagtplan
+
+ Ændre din fornavn eller efternavn.
+
+
+
+
+
+
+
+
+ Ydelser
+
+ Tilføj eller opdater dine ydelser.
+
+
+
+
+
+
+
+
+ Kalendar
+
+ Administrer dine kunde bookinger
+
+
+
+
+
+
+
+
+ Ferie
+
+ Planlæg og administrer dine ferier
+
+
+
+
+
+
+
+
+ Udbetalinger
+
+ Administrer dine udbetalinger
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/routes/account.api.booked.tsx b/app/routes/business.api.booked.tsx
similarity index 100%
rename from app/routes/account.api.booked.tsx
rename to app/routes/business.api.booked.tsx
diff --git a/app/routes/account.api.bookings.tsx b/app/routes/business.api.bookings.tsx
similarity index 100%
rename from app/routes/account.api.bookings.tsx
rename to app/routes/business.api.bookings.tsx
diff --git a/app/routes/account.api.products.tsx b/app/routes/business.api.products.tsx
similarity index 100%
rename from app/routes/account.api.products.tsx
rename to app/routes/business.api.products.tsx
diff --git a/app/routes/account.booked.$blockedId.destroy.tsx b/app/routes/business.booked.$blockedId.destroy.tsx
similarity index 100%
rename from app/routes/account.booked.$blockedId.destroy.tsx
rename to app/routes/business.booked.$blockedId.destroy.tsx
diff --git a/app/routes/account.booked.create.tsx b/app/routes/business.booked.create.tsx
similarity index 100%
rename from app/routes/account.booked.create.tsx
rename to app/routes/business.booked.create.tsx
diff --git a/app/routes/account.booked.tsx b/app/routes/business.booked.tsx
similarity index 92%
rename from app/routes/account.booked.tsx
rename to app/routes/business.booked.tsx
index 3669c96a..d981e47d 100644
--- a/app/routes/account.booked.tsx
+++ b/app/routes/business.booked.tsx
@@ -1,4 +1,4 @@
-import {Button, Modal, ScrollArea, Table} from '@mantine/core';
+import {Button, Container, Modal, rem, ScrollArea, Table} from '@mantine/core';
import {useMediaQuery} from '@mantine/hooks';
import {
Form,
@@ -66,8 +66,8 @@ export default function AccountBookings() {
));
return (
- <>
-
+
+
Tilføj ferie
@@ -97,6 +97,6 @@ export default function AccountBookings() {
- >
+
);
}
diff --git a/app/routes/account.bookings.$orderId.group.$groupId.tsx b/app/routes/business.bookings.$orderId.group.$groupId.tsx
similarity index 100%
rename from app/routes/account.bookings.$orderId.group.$groupId.tsx
rename to app/routes/business.bookings.$orderId.group.$groupId.tsx
diff --git a/app/routes/account.bookings.tsx b/app/routes/business.bookings.tsx
similarity index 97%
rename from app/routes/account.bookings.tsx
rename to app/routes/business.bookings.tsx
index 762a9aef..0db6df07 100644
--- a/app/routes/account.bookings.tsx
+++ b/app/routes/business.bookings.tsx
@@ -4,7 +4,7 @@ import dayGridPlugin from '@fullcalendar/daygrid';
import interactionPlugin from '@fullcalendar/interaction';
import FullCalendar from '@fullcalendar/react';
import timeGridPlugin from '@fullcalendar/timegrid';
-import {Modal} from '@mantine/core';
+import {Container, Modal, rem} from '@mantine/core';
import {useMediaQuery} from '@mantine/hooks';
import {Outlet, useNavigate, useOutlet} from '@remix-run/react';
import {AccountContent} from '~/components/account/AccountContent';
@@ -37,7 +37,7 @@ export default function AccountBookings() {
};
return (
- <>
+
- >
+
);
}
diff --git a/app/routes/account.locations.$locationId._index.tsx b/app/routes/business.locations.$locationId._index.tsx
similarity index 100%
rename from app/routes/account.locations.$locationId._index.tsx
rename to app/routes/business.locations.$locationId._index.tsx
diff --git a/app/routes/account.locations.$locationId.destroy.tsx b/app/routes/business.locations.$locationId.destroy.tsx
similarity index 100%
rename from app/routes/account.locations.$locationId.destroy.tsx
rename to app/routes/business.locations.$locationId.destroy.tsx
diff --git a/app/routes/account.locations.$locationId.products.tsx b/app/routes/business.locations.$locationId.products.tsx
similarity index 100%
rename from app/routes/account.locations.$locationId.products.tsx
rename to app/routes/business.locations.$locationId.products.tsx
diff --git a/app/routes/account.locations.$locationId.tsx b/app/routes/business.locations.$locationId.tsx
similarity index 91%
rename from app/routes/account.locations.$locationId.tsx
rename to app/routes/business.locations.$locationId.tsx
index 28124a9c..1f7c67c7 100644
--- a/app/routes/account.locations.$locationId.tsx
+++ b/app/routes/business.locations.$locationId.tsx
@@ -4,7 +4,7 @@ import {type LoaderFunctionArgs} from '@shopify/remix-oxygen';
import {getBookingShopifyApi} from '~/lib/api/bookingShopifyApi';
import {getCustomer} from '~/lib/get-customer';
-import {Button} from '@mantine/core';
+import {Button, Container, rem} from '@mantine/core';
import {jsonWithSuccess} from 'remix-toast';
import {AccountButton} from '~/components/account/AccountButton';
import {AccountContent} from '~/components/account/AccountContent';
@@ -31,8 +31,8 @@ export default function AccountLocationsEdit() {
const defaultValue = useLoaderData();
return (
- <>
-
+
+
Basic detaljer
@@ -76,6 +76,6 @@ export default function AccountLocationsEdit() {
- >
+
);
}
diff --git a/app/routes/account.locations._index.tsx b/app/routes/business.locations._index.tsx
similarity index 97%
rename from app/routes/account.locations._index.tsx
rename to app/routes/business.locations._index.tsx
index ee632f8b..91c7f9e9 100644
--- a/app/routes/account.locations._index.tsx
+++ b/app/routes/business.locations._index.tsx
@@ -1,6 +1,7 @@
import {
Button,
Card,
+ Container,
Flex,
rem,
SimpleGrid,
@@ -35,8 +36,8 @@ export default function AccountLocationsIndex() {
const {locations} = useLoaderData();
return (
- <>
-
+
+
}
@@ -81,7 +82,7 @@ export default function AccountLocationsIndex() {
))}
- >
+
);
}
diff --git a/app/routes/account.locations.create.tsx b/app/routes/business.locations.create.tsx
similarity index 96%
rename from app/routes/account.locations.create.tsx
rename to app/routes/business.locations.create.tsx
index 782ff0f5..a773ef01 100644
--- a/app/routes/account.locations.create.tsx
+++ b/app/routes/business.locations.create.tsx
@@ -10,7 +10,7 @@ import {customerLocationCreateBody} from '~/lib/zod/bookingShopifyApi';
import {getFormProps, getInputProps, useForm} from '@conform-to/react';
import {parseWithZod} from '@conform-to/zod';
-import {Stack, TextInput} from '@mantine/core';
+import {Container, rem, Stack, TextInput} from '@mantine/core';
import {redirectWithSuccess} from 'remix-toast';
import {AccountContent} from '~/components/account/AccountContent';
import {AccountTitle} from '~/components/account/AccountTitle';
@@ -85,8 +85,11 @@ export default function Component() {
});
return (
- <>
-
+
+
- >
+
);
}
diff --git a/app/routes/account.locations.tsx b/app/routes/business.locations.tsx
similarity index 100%
rename from app/routes/account.locations.tsx
rename to app/routes/business.locations.tsx
diff --git a/app/routes/account.payouts.$id.tsx b/app/routes/business.payouts.$id.tsx
similarity index 96%
rename from app/routes/account.payouts.$id.tsx
rename to app/routes/business.payouts.$id.tsx
index f0953d88..3588effb 100644
--- a/app/routes/account.payouts.$id.tsx
+++ b/app/routes/business.payouts.$id.tsx
@@ -1,4 +1,4 @@
-import {Card, Stack, Table, Text} from '@mantine/core';
+import {Card, Container, rem, Stack, Table, Text} from '@mantine/core';
import {defer, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
import {getCustomer} from '~/lib/get-customer';
@@ -16,7 +16,7 @@ import type {
CustomerPayoutLogResponse,
Shipping,
} from '~/lib/api/model';
-import {isMobilePay} from './account.payouts';
+import {isMobilePay} from './business.payouts';
export function isShipping(
details: CustomerPayoutLogReferenceDocument,
@@ -45,7 +45,7 @@ export default function AccountPayoutsId() {
const data = useLoaderData();
return (
- <>
+
@@ -54,7 +54,7 @@ export default function AccountPayoutsId() {
- >
+
);
}
diff --git a/app/routes/account.payouts._index.tsx b/app/routes/business.payouts._index.tsx
similarity index 96%
rename from app/routes/account.payouts._index.tsx
rename to app/routes/business.payouts._index.tsx
index eb9478d6..4d15aee6 100644
--- a/app/routes/account.payouts._index.tsx
+++ b/app/routes/business.payouts._index.tsx
@@ -2,6 +2,8 @@ import {
Badge,
Button,
Card,
+ Container,
+ rem,
SimpleGrid,
Skeleton,
Stack,
@@ -22,7 +24,7 @@ import type {
CustomerPayoutBalanceResponse,
} from '~/lib/api/model';
import {getCustomer} from '~/lib/get-customer';
-import {isMobilePay} from './account.payouts';
+import {isMobilePay} from './business.payouts';
export async function loader({context}: LoaderFunctionArgs) {
const customerId = await getCustomer({context});
@@ -43,8 +45,8 @@ export default function AccountPayoutsIndex() {
const data = useLoaderData();
return (
- <>
-
+
+
@@ -114,7 +116,7 @@ export default function AccountPayoutsIndex() {
- >
+
);
}
diff --git a/app/routes/account.payouts.create.tsx b/app/routes/business.payouts.create.tsx
similarity index 97%
rename from app/routes/account.payouts.create.tsx
rename to app/routes/business.payouts.create.tsx
index 394603e2..61acca67 100644
--- a/app/routes/account.payouts.create.tsx
+++ b/app/routes/business.payouts.create.tsx
@@ -1,8 +1,10 @@
import {parseWithZod} from '@conform-to/zod';
import {
+ Container,
Flex,
InputBase,
Radio,
+ rem,
Stack,
Text,
TextInput,
@@ -26,7 +28,7 @@ import {SubmitButton} from '~/components/form/SubmitButton';
import {getBookingShopifyApi} from '~/lib/api/bookingShopifyApi';
import {CustomerPayoutAccountType} from '~/lib/api/model';
import {customerPayoutAccountCreateBody} from '~/lib/zod/bookingShopifyApi';
-import {isMobilePay} from './account.payouts';
+import {isMobilePay} from './business.payouts';
const schema = customerPayoutAccountCreateBody;
@@ -95,7 +97,7 @@ export default function AccountPayoutsSettings() {
const payoutType = useInputControl(fields.payoutType);
return (
- <>
+
@@ -180,6 +182,6 @@ export default function AccountPayoutsSettings() {
- >
+
);
}
diff --git a/app/routes/account.payouts.destroy.tsx b/app/routes/business.payouts.destroy.tsx
similarity index 100%
rename from app/routes/account.payouts.destroy.tsx
rename to app/routes/business.payouts.destroy.tsx
diff --git a/app/routes/account.payouts.request.tsx b/app/routes/business.payouts.request.tsx
similarity index 100%
rename from app/routes/account.payouts.request.tsx
rename to app/routes/business.payouts.request.tsx
diff --git a/app/routes/account.payouts.tsx b/app/routes/business.payouts.tsx
similarity index 100%
rename from app/routes/account.payouts.tsx
rename to app/routes/business.payouts.tsx
diff --git a/app/routes/account.public._index.tsx b/app/routes/business.public._index.tsx
similarity index 100%
rename from app/routes/account.public._index.tsx
rename to app/routes/business.public._index.tsx
diff --git a/app/routes/account.public.social.tsx b/app/routes/business.public.social.tsx
similarity index 100%
rename from app/routes/account.public.social.tsx
rename to app/routes/business.public.social.tsx
diff --git a/app/routes/account.public.theme.tsx b/app/routes/business.public.theme.tsx
similarity index 100%
rename from app/routes/account.public.theme.tsx
rename to app/routes/business.public.theme.tsx
diff --git a/app/routes/account.public.tsx b/app/routes/business.public.tsx
similarity index 69%
rename from app/routes/account.public.tsx
rename to app/routes/business.public.tsx
index ba85d176..f4830c9e 100644
--- a/app/routes/account.public.tsx
+++ b/app/routes/business.public.tsx
@@ -1,4 +1,4 @@
-import {Group} from '@mantine/core';
+import {Container, Group, rem} from '@mantine/core';
import {Outlet} from '@remix-run/react';
import {AccountButton} from '~/components/account/AccountButton';
@@ -7,19 +7,19 @@ import {AccountTitle} from '~/components/account/AccountTitle';
export default function AccountBusiness() {
return (
- <>
-
+
+
Profil
Social Media
Tema
- Skift billed
+ Skift billed
- >
+
);
}
diff --git a/app/routes/account.upload.tsx b/app/routes/business.public.upload.tsx
similarity index 68%
rename from app/routes/account.upload.tsx
rename to app/routes/business.public.upload.tsx
index 421a0185..341f03ac 100644
--- a/app/routes/account.upload.tsx
+++ b/app/routes/business.public.upload.tsx
@@ -13,8 +13,6 @@ import {
import {IconFileCv, IconInfoCircle} from '@tabler/icons-react';
import {useEffect, useRef, useState} from 'react';
import {redirectWithSuccess} from 'remix-toast';
-import {AccountContent} from '~/components/account/AccountContent';
-import {AccountTitle} from '~/components/account/AccountTitle';
import {getBookingShopifyApi} from '~/lib/api/bookingShopifyApi';
import {getCustomer} from '~/lib/get-customer';
@@ -116,53 +114,49 @@ export default function AccountUpload() {
return (
<>
-
-
-
- {imageUploaded ? (
- }
- >
- Vi har modtaget dit billed, der går lidt tid før du ser dit billed
- opdateret.
-
- ) : (
-
- )}
-
+ {imageUploaded ? (
+ }
+ >
+ Vi har modtaget dit billed, der går lidt tid før du ser dit billed
+ opdateret.
+
+ ) : (
+
+ )}
>
);
}
diff --git a/app/routes/account.schedules.$scheduleHandle.destroy.tsx b/app/routes/business.schedules.$scheduleHandle.destroy.tsx
similarity index 100%
rename from app/routes/account.schedules.$scheduleHandle.destroy.tsx
rename to app/routes/business.schedules.$scheduleHandle.destroy.tsx
diff --git a/app/routes/account.schedules.$scheduleHandle.edit.tsx b/app/routes/business.schedules.$scheduleHandle.edit.tsx
similarity index 100%
rename from app/routes/account.schedules.$scheduleHandle.edit.tsx
rename to app/routes/business.schedules.$scheduleHandle.edit.tsx
diff --git a/app/routes/account.schedules.$scheduleHandle.tsx b/app/routes/business.schedules.$scheduleHandle.tsx
similarity index 100%
rename from app/routes/account.schedules.$scheduleHandle.tsx
rename to app/routes/business.schedules.$scheduleHandle.tsx
diff --git a/app/routes/account.schedules.create.tsx b/app/routes/business.schedules.create.tsx
similarity index 100%
rename from app/routes/account.schedules.create.tsx
rename to app/routes/business.schedules.create.tsx
diff --git a/app/routes/account.schedules.tsx b/app/routes/business.schedules.tsx
similarity index 93%
rename from app/routes/account.schedules.tsx
rename to app/routes/business.schedules.tsx
index 20216c31..f71e8156 100644
--- a/app/routes/account.schedules.tsx
+++ b/app/routes/business.schedules.tsx
@@ -1,5 +1,6 @@
import {
Button,
+ Container,
Divider,
Flex,
rem,
@@ -23,7 +24,7 @@ import {AccountContent} from '~/components/account/AccountContent';
import {AccountTitle} from '~/components/account/AccountTitle';
import {getBookingShopifyApi} from '~/lib/api/bookingShopifyApi';
import {getCustomer} from '~/lib/get-customer';
-import {AccountSchedulesCreate} from './account.schedules.create';
+import {AccountSchedulesCreate} from './business.schedules.create';
export async function loader({context, request}: LoaderFunctionArgs) {
const customerId = await getCustomer({context});
@@ -76,8 +77,8 @@ export default function AccountSchedulesIndex() {
) : null;
return (
- <>
-
+
+
- >
+
);
}
diff --git a/app/routes/account.services.$productId._index.tsx b/app/routes/business.services.$productId._index.tsx
similarity index 100%
rename from app/routes/account.services.$productId._index.tsx
rename to app/routes/business.services.$productId._index.tsx
diff --git a/app/routes/account.services.$productId.configuration.tsx b/app/routes/business.services.$productId.configuration.tsx
similarity index 100%
rename from app/routes/account.services.$productId.configuration.tsx
rename to app/routes/business.services.$productId.configuration.tsx
diff --git a/app/routes/account.services.$productId.destroy.tsx b/app/routes/business.services.$productId.destroy.tsx
similarity index 100%
rename from app/routes/account.services.$productId.destroy.tsx
rename to app/routes/business.services.$productId.destroy.tsx
diff --git a/app/routes/account.services.$productId.options.$optionProductId.update.tsx b/app/routes/business.services.$productId.options.$optionProductId.update.tsx
similarity index 100%
rename from app/routes/account.services.$productId.options.$optionProductId.update.tsx
rename to app/routes/business.services.$productId.options.$optionProductId.update.tsx
diff --git a/app/routes/account.services.$productId.options.add.tsx b/app/routes/business.services.$productId.options.add.tsx
similarity index 100%
rename from app/routes/account.services.$productId.options.add.tsx
rename to app/routes/business.services.$productId.options.add.tsx
diff --git a/app/routes/account.services.$productId.options.destroy.tsx b/app/routes/business.services.$productId.options.destroy.tsx
similarity index 100%
rename from app/routes/account.services.$productId.options.destroy.tsx
rename to app/routes/business.services.$productId.options.destroy.tsx
diff --git a/app/routes/account.services.$productId.options.tsx b/app/routes/business.services.$productId.options.tsx
similarity index 99%
rename from app/routes/account.services.$productId.options.tsx
rename to app/routes/business.services.$productId.options.tsx
index a6eeff7d..8fbd006a 100644
--- a/app/routes/account.services.$productId.options.tsx
+++ b/app/routes/business.services.$productId.options.tsx
@@ -12,7 +12,7 @@ import {
type SerializeFrom,
} from '@shopify/remix-oxygen';
import {getCustomer} from '~/lib/get-customer';
-import {type loader as rootLoader} from './account.services.$productId';
+import {type loader as rootLoader} from './business.services.$productId';
import {
Accordion,
diff --git a/app/routes/account.services.$productId.tsx b/app/routes/business.services.$productId.tsx
similarity index 93%
rename from app/routes/account.services.$productId.tsx
rename to app/routes/business.services.$productId.tsx
index bde48242..2560a802 100644
--- a/app/routes/account.services.$productId.tsx
+++ b/app/routes/business.services.$productId.tsx
@@ -1,4 +1,4 @@
-import {Button} from '@mantine/core';
+import {Button, Container, rem} from '@mantine/core';
import {Form, Outlet, useLoaderData} from '@remix-run/react';
import {json, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
import {AccountButton} from '~/components/account/AccountButton';
@@ -28,7 +28,7 @@ export default function EditAddress() {
const {product} = useLoaderData();
return (
- <>
+
- >
+
);
}
diff --git a/app/routes/account.services._index.tsx b/app/routes/business.services._index.tsx
similarity index 95%
rename from app/routes/account.services._index.tsx
rename to app/routes/business.services._index.tsx
index bd38c3f3..8c5f5d59 100644
--- a/app/routes/account.services._index.tsx
+++ b/app/routes/business.services._index.tsx
@@ -2,6 +2,7 @@ import {
ActionIcon,
Button,
Card,
+ Container,
Divider,
Flex,
Grid,
@@ -37,8 +38,8 @@ export default function AccountServicesIndex() {
const {user} = useOutletContext();
return (
- <>
-
+
+
}
@@ -76,10 +77,7 @@ export default function AccountServicesIndex() {
{products.map((product) => {
return (
-
+
)}
- >
+
);
}
diff --git a/app/routes/account.services.create.tsx b/app/routes/business.services.create.tsx
similarity index 98%
rename from app/routes/account.services.create.tsx
rename to app/routes/business.services.create.tsx
index 5ac29839..8130dfaa 100644
--- a/app/routes/account.services.create.tsx
+++ b/app/routes/business.services.create.tsx
@@ -8,8 +8,10 @@ import {
import {parseWithZod} from '@conform-to/zod';
import {
+ Container,
Divider,
Flex,
+ rem,
Select,
Stack,
Switch,
@@ -178,8 +180,8 @@ export default function AccountServicesCreate() {
};
return (
- <>
-
+
+
- >
+
);
}
diff --git a/app/routes/account.services.tsx b/app/routes/business.services.tsx
similarity index 88%
rename from app/routes/account.services.tsx
rename to app/routes/business.services.tsx
index 82987e47..bb06a1bf 100644
--- a/app/routes/account.services.tsx
+++ b/app/routes/business.services.tsx
@@ -1,4 +1,4 @@
-import {Button, Flex, rem, ThemeIcon, Title} from '@mantine/core';
+import {Button, Container, Flex, rem, ThemeIcon, Title} from '@mantine/core';
import {Link, Outlet, useLoaderData, useOutletContext} from '@remix-run/react';
import {json, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
@@ -29,8 +29,8 @@ export default function AccountServices() {
if (!status.locations) {
return (
- <>
-
+
+
@@ -52,13 +52,13 @@ export default function AccountServices() {
- >
+
);
}
if (!status.schedules) {
return (
- <>
+
@@ -77,7 +77,7 @@ export default function AccountServices() {
- >
+
);
}
diff --git a/app/routes/business.tsx b/app/routes/business.tsx
new file mode 100644
index 00000000..232df024
--- /dev/null
+++ b/app/routes/business.tsx
@@ -0,0 +1,106 @@
+import tiptapStyles from '@mantine/tiptap/styles.css?url';
+import {
+ Outlet,
+ useLoaderData,
+ type ShouldRevalidateFunction,
+} from '@remix-run/react';
+import {parseGid} from '@shopify/hydrogen';
+import {json, redirect, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
+import {type CustomerFragment} from 'customer-accountapi.generated';
+import {useEffect} from 'react';
+import notify, {Toaster} from 'react-hot-toast';
+import {getToast} from 'remix-toast';
+import {CUSTOMER_DETAILS_QUERY} from '~/graphql/customer-account/CustomerDetailsQuery';
+import {getBookingShopifyApi} from '~/lib/api/bookingShopifyApi';
+import {type User} from '~/lib/api/model';
+
+export function links() {
+ return [{rel: 'stylesheet', href: tiptapStyles}];
+}
+export type AccountOutlet = {
+ customer: CustomerFragment;
+ user?: User | null;
+ isBusiness: boolean;
+};
+
+export const shouldRevalidate: ShouldRevalidateFunction = ({
+ formMethod,
+ currentUrl,
+ nextUrl,
+}) => {
+ if (formMethod && formMethod !== 'GET') {
+ return true;
+ }
+
+ // revalidate when manually revalidating via useRevalidator
+ if (currentUrl.toString() === nextUrl.toString()) {
+ return true;
+ }
+
+ return false;
+};
+
+export async function loader({context, request}: LoaderFunctionArgs) {
+ const {data, errors} = await context.customerAccount.query(
+ CUSTOMER_DETAILS_QUERY,
+ );
+
+ if (errors?.length || !data?.customer) {
+ throw new Error('Customer not found');
+ }
+
+ if (!data.customer.tags.includes('business')) {
+ return redirect('/account');
+ }
+
+ const {payload} = await getBookingShopifyApi().customerGet(
+ parseGid(data.customer.id).id,
+ );
+
+ const {toast} = await getToast(request);
+
+ return json(
+ {
+ customer: data.customer,
+ user: payload,
+ toast,
+ },
+ {
+ headers: {
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
+ 'Set-Cookie': await context.session.commit(),
+ },
+ },
+ );
+}
+
+export default function Acccount() {
+ const {customer, user, toast} = useLoaderData();
+
+ useEffect(() => {
+ if (toast) {
+ switch (toast.type) {
+ case 'success':
+ notify.success(toast.message);
+ return;
+ case 'error':
+ notify.error(toast.message);
+
+ return;
+ default:
+ return;
+ }
+ }
+ }, [toast]);
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/app/routes/users.tsx b/app/routes/users.tsx
index 791bbc7c..b62b2dae 100644
--- a/app/routes/users.tsx
+++ b/app/routes/users.tsx
@@ -56,7 +56,7 @@ import {
} from '~/components/filters/LocationFilter';
import {ProfessionButton} from '~/components/ProfessionButton';
import {getTags} from '~/lib/tags';
-import {COLLECTION} from './account.services.create';
+import {COLLECTION} from './business.services.create';
import {PAGE_QUERY} from './pages.$handle';
export const handle: Handle = {
diff --git a/customer-accountapi.generated.d.ts b/customer-accountapi.generated.d.ts
index 433a1636..d078a0bb 100644
--- a/customer-accountapi.generated.d.ts
+++ b/customer-accountapi.generated.d.ts
@@ -68,8 +68,14 @@ export type CustomerAddressCreateMutation = {
export type CustomerFragment = Pick<
CustomerAccountAPI.Customer,
- 'id' | 'firstName' | 'lastName'
+ 'id' | 'firstName' | 'lastName' | 'tags'
> & {
+ emailAddress?: CustomerAccountAPI.Maybe<
+ Pick<
+ CustomerAccountAPI.CustomerEmailAddress,
+ 'emailAddress' | 'marketingState'
+ >
+ >;
defaultAddress?: CustomerAccountAPI.Maybe<
Pick<
CustomerAccountAPI.CustomerAddress,
@@ -131,8 +137,14 @@ export type CustomerDetailsQueryVariables = CustomerAccountAPI.Exact<{
export type CustomerDetailsQuery = {
customer: Pick<
CustomerAccountAPI.Customer,
- 'id' | 'firstName' | 'lastName'
+ 'id' | 'firstName' | 'lastName' | 'tags'
> & {
+ emailAddress?: CustomerAccountAPI.Maybe<
+ Pick<
+ CustomerAccountAPI.CustomerEmailAddress,
+ 'emailAddress' | 'marketingState'
+ >
+ >;
defaultAddress?: CustomerAccountAPI.Maybe<
Pick<
CustomerAccountAPI.CustomerAddress,
@@ -477,7 +489,7 @@ export type CustomerUpdateMutation = {
};
interface GeneratedQueryTypes {
- '#graphql\n query CustomerDetails {\n customer {\n ...Customer\n }\n }\n #graphql\n fragment Customer on Customer {\n id\n firstName\n lastName\n defaultAddress {\n ...Address\n }\n addresses(first: 6) {\n nodes {\n ...Address\n }\n }\n }\n fragment Address on CustomerAddress {\n id\n formatted\n firstName\n lastName\n company\n address1\n address2\n territoryCode\n zoneCode\n city\n zip\n phoneNumber\n }\n\n': {
+ '#graphql\n query CustomerDetails {\n customer {\n ...Customer\n }\n }\n #graphql\n fragment Customer on Customer {\n id\n firstName\n lastName\n emailAddress {\n emailAddress\n marketingState\n }\n tags\n defaultAddress {\n ...Address\n }\n addresses(first: 6) {\n nodes {\n ...Address\n }\n }\n }\n fragment Address on CustomerAddress {\n id\n formatted\n firstName\n lastName\n company\n address1\n address2\n territoryCode\n zoneCode\n city\n zip\n phoneNumber\n }\n\n': {
return: CustomerDetailsQuery;
variables: CustomerDetailsQueryVariables;
};
diff --git a/public/locales/ar/account.json b/public/locales/ar/account.json
new file mode 100644
index 00000000..44198e05
--- /dev/null
+++ b/public/locales/ar/account.json
@@ -0,0 +1,70 @@
+{
+ "business_title": "شريك",
+ "business_text": "اذهب إلى العمل",
+ "business_action": "اذهب إلى العمل",
+ "orders_title": "الحجوزات",
+ "orders_text": "إدارة حجوزاتك السابقة والقادمة.",
+ "profile_title": "معلومات شخصية",
+ "profile_text": "قم بتغيير اسمك الأول أو الأخير.",
+ "address_title": "العناوين",
+ "address_text": "إدارة عناوينك",
+ "partner_title": "شريك",
+ "partner_text": "ابدأ مسيرتك في مجال الجمال",
+ "partner_action": "ابدأ الآن",
+ "profile": {
+ "title": "معلومات شخصية",
+ "error": "خطأ",
+ "first_name": "الاسم الأول",
+ "last_name": "الاسم الأخير",
+ "save": "حفظ التغييرات"
+ },
+ "orders": {
+ "title": "الطلبات",
+ "date": "التاريخ",
+ "payment": "الدفع",
+ "status": "الحالة",
+ "total": "المبلغ",
+ "empty": "لم تقم بوضع أي طلبات حتى الآن",
+ "goto_frontpage": "اذهب إلى الصفحة الرئيسية",
+ "id": {
+ "title": "طلب {{name}}",
+ "bought": "تم الشراء",
+ "products": "المنتجات",
+ "image": "صورة",
+ "description": "الوصف",
+ "total": "المجموع",
+ "summary": "الملخص",
+ "discount": "الخصم",
+ "subtotal": "الإجمالي الفرعي",
+ "tax": "الضريبة",
+ "shipping": "الشحن",
+ "no_shipping": "لا يوجد شحن",
+ "treatments": "العلاجات",
+ "details": "التفاصيل",
+ "visiting": "زيارة <0>{{name}}0>",
+ "visiting_deleted": "تم حذف ملف الجمال",
+ "time": "الوقت",
+ "location": "الموقع",
+ "location_expenses": "سيتم حساب النفقات أثناء عملية الشراء."
+ }
+ },
+ "address": {
+ "title": "العناوين",
+ "creating": "إنشاء...",
+ "create": "إنشاء عنوان",
+ "edit": "تعديل العنوان",
+ "saving": "حفظ...",
+ "save": "حفظ",
+ "deleting": "حذف...",
+ "delete": "حذف",
+ "form": {
+ "first_name": "الاسم الأول",
+ "last_name": "الاسم الأخير",
+ "address": "العنوان",
+ "zip": "الرمز البريدي",
+ "city": "المدينة",
+ "phone": "رقم الهاتف",
+ "default_address": "تعيين كعنوان افتراضي"
+ }
+ }
+}
diff --git a/public/locales/ar/global.json b/public/locales/ar/global.json
index 05a17fb8..f3b70f7c 100644
--- a/public/locales/ar/global.json
+++ b/public/locales/ar/global.json
@@ -5,6 +5,7 @@
"english": "إنجليزي",
"arabic": "عربي",
"login": "تسجيل الدخول",
+ "logout": "تسجيل الخروج",
"monday": "الإثنين",
"tuesday": "الثلاثاء",
"wednesday": "الأربعاء",
diff --git a/public/locales/da/account.json b/public/locales/da/account.json
new file mode 100644
index 00000000..8bbe42a8
--- /dev/null
+++ b/public/locales/da/account.json
@@ -0,0 +1,70 @@
+{
+ "business_title": "Partner",
+ "business_text": "Gå til business",
+ "business_action": "Gå til business",
+ "orders_title": "Bookinger",
+ "orders_text": "Administrer dine tidligere og kommende bookinger.",
+ "profile_title": "Personlig oplysninger",
+ "profile_text": "Ændre din fornavn eller efternavn.",
+ "address_title": "Adresser",
+ "address_text": "Administrer dine adresser",
+ "partner_title": "Partner",
+ "partner_text": "Start din skønhedskarrier",
+ "partner_action": "Kom igang",
+ "profile": {
+ "title": "Personlige oplysninger",
+ "error": "Fejl",
+ "first_name": "Fornavn",
+ "last_name": "Efternavn",
+ "save": "Gem ændringer"
+ },
+ "orders": {
+ "title": "Ordre",
+ "date": "Dato",
+ "payment": "Betaling",
+ "status": "Status",
+ "total": "Beløb",
+ "empty": "Du har ikke afgivet nogen ordre endnu",
+ "goto_frontpage": "Gå til forside",
+ "id": {
+ "title": "Ordre {{name}}",
+ "bought": "Købt",
+ "products": "Produkter",
+ "image": "Billed",
+ "description": "Beskrivelse",
+ "total": "Total",
+ "summary": "Summary",
+ "discount": "Rabat",
+ "subtotal": "Subtotal",
+ "tax": "Moms",
+ "shipping": "Forsendelse",
+ "no_shipping": "Ingen forsendelse",
+ "treatments": "Behandlinger",
+ "details": "Detaljer",
+ "visiting": "Hos <0>{{name}}0>",
+ "visiting_deleted": "Skønhedsprofil er slettet",
+ "time": "Tid",
+ "location": "Location",
+ "location_expenses": "Udgifterne bliver beregnet under købsprocessen."
+ }
+ },
+ "address": {
+ "title": "Adresser",
+ "creating": "Opretter...",
+ "create": "Opret adresse",
+ "edit": "Ændre adresse",
+ "saving": "Gemmer...",
+ "save": "Gem",
+ "deleting": "Sletter...",
+ "delete": "Slet",
+ "form": {
+ "first_name": "Fornavn",
+ "last_name": "Efternavn",
+ "address": "Adresse",
+ "zip": "Postnummer",
+ "city": "By",
+ "phone": "Telefonnummer",
+ "default_address": "Indstil som standardadresse"
+ }
+ }
+}
diff --git a/public/locales/da/global.json b/public/locales/da/global.json
index 50b73e63..435d8ab5 100644
--- a/public/locales/da/global.json
+++ b/public/locales/da/global.json
@@ -5,6 +5,7 @@
"english": "Engelsk",
"arabic": "Arabisk",
"login": "Log ind",
+ "logout": "Log ud",
"monday": "Mandag",
"tuesday": "Tirsdag",
"wednesday": "Onsdag",
diff --git a/public/locales/en/account.json b/public/locales/en/account.json
new file mode 100644
index 00000000..e9e0dd1d
--- /dev/null
+++ b/public/locales/en/account.json
@@ -0,0 +1,70 @@
+{
+ "business_title": "Partner",
+ "business_text": "Go to business",
+ "business_action": "Go to business",
+ "orders_title": "Bookings",
+ "orders_text": "Manage your past and upcoming bookings.",
+ "profile_title": "Personal Information",
+ "profile_text": "Change your first or last name.",
+ "address_title": "Addresses",
+ "address_text": "Manage your addresses",
+ "partner_title": "Partner",
+ "partner_text": "Start your beauty career",
+ "partner_action": "Get started",
+ "profile": {
+ "title": "Personal Information",
+ "error": "Error",
+ "first_name": "First Name",
+ "last_name": "Last Name",
+ "save": "Save Changes"
+ },
+ "orders": {
+ "title": "Orders",
+ "date": "Date",
+ "payment": "Payment",
+ "status": "Status",
+ "total": "Amount",
+ "empty": "You have not placed any orders yet",
+ "goto_frontpage": "Go to Frontpage",
+ "id": {
+ "title": "Order {{name}}",
+ "bought": "Bought",
+ "products": "Products",
+ "image": "Image",
+ "description": "Description",
+ "total": "Total",
+ "summary": "Summary",
+ "discount": "Discount",
+ "subtotal": "Subtotal",
+ "tax": "Tax",
+ "shipping": "Shipping",
+ "no_shipping": "No shipping",
+ "treatments": "Treatments",
+ "details": "Details",
+ "visiting": "Visiting <0>{{name}}0>",
+ "visiting_deleted": "Beauty profile deleted",
+ "time": "Time",
+ "location": "Location",
+ "location_expenses": "Expenses will be calculated during the purchase process."
+ }
+ },
+ "address": {
+ "title": "Addresses",
+ "creating": "Creating...",
+ "create": "Create Address",
+ "edit": "Edit Address",
+ "saving": "Saving...",
+ "save": "Save",
+ "deleting": "Deleting...",
+ "delete": "Delete",
+ "form": {
+ "first_name": "First Name",
+ "last_name": "Last Name",
+ "address": "Address",
+ "zip": "Zip Code",
+ "city": "City",
+ "phone": "Phone Number",
+ "default_address": "Set as default address"
+ }
+ }
+}
diff --git a/public/locales/en/global.json b/public/locales/en/global.json
index bf29c539..02709028 100644
--- a/public/locales/en/global.json
+++ b/public/locales/en/global.json
@@ -5,6 +5,7 @@
"english": "English",
"arabic": "Arabic",
"login": "Login",
+ "logout": "Log out",
"monday": "Monday",
"tuesday": "Tuesday",
"wednesday": "Wednesday",
diff --git a/storefrontapi.generated.d.ts b/storefrontapi.generated.d.ts
index 7c78ff91..213a8c65 100644
--- a/storefrontapi.generated.d.ts
+++ b/storefrontapi.generated.d.ts
@@ -2808,148 +2808,6 @@ export type RecommendedTreatmentsQuery = {
};
};
-export type ProductSearchSimpleFragment = Pick<
- StorefrontAPI.Product,
- 'id' | 'title' | 'handle'
->;
-
-export type ProductSearchQueryQueryVariables = StorefrontAPI.Exact<{
- collectionId: StorefrontAPI.Scalars['ID']['input'];
- country?: StorefrontAPI.InputMaybe;
- language?: StorefrontAPI.InputMaybe;
- first?: StorefrontAPI.InputMaybe;
-}>;
-
-export type ProductSearchQueryQuery = {
- collection?: StorefrontAPI.Maybe<{
- products: {
- nodes: Array>;
- };
- }>;
-};
-
-export type ProductVariantIdsQueryVariables = StorefrontAPI.Exact<{
- country?: StorefrontAPI.InputMaybe;
- language?: StorefrontAPI.InputMaybe;
- variantId:
- | Array
- | StorefrontAPI.Scalars['ID']['input'];
-}>;
-
-export type ProductVariantIdsQuery = {
- nodes: Array<
- StorefrontAPI.Maybe<
- Pick<
- StorefrontAPI.ProductVariant,
- 'availableForSale' | 'id' | 'sku' | 'title'
- > & {
- compareAtPrice?: StorefrontAPI.Maybe<
- Pick
- >;
- image?: StorefrontAPI.Maybe<
- {__typename: 'Image'} & Pick<
- StorefrontAPI.Image,
- 'id' | 'url' | 'altText' | 'width' | 'height'
- >
- >;
- price: Pick;
- product: Pick;
- selectedOptions: Array<
- Pick
- >;
- unitPrice?: StorefrontAPI.Maybe<
- Pick
- >;
- }
- >
- >;
-};
-
-export type ServicesOptionsTagProductFragment = Pick<
- StorefrontAPI.Product,
- 'id' | 'handle' | 'title'
-> & {
- options: Array>;
- variants: {
- nodes: Array<
- Pick & {
- price: Pick;
- }
- >;
- };
-};
-
-export type ServicesOptionsTagOptionsQueryQueryVariables = StorefrontAPI.Exact<{
- country?: StorefrontAPI.InputMaybe;
- language?: StorefrontAPI.InputMaybe;
- query: StorefrontAPI.Scalars['String']['input'];
- first?: StorefrontAPI.InputMaybe;
-}>;
-
-export type ServicesOptionsTagOptionsQueryQuery = {
- products: {
- nodes: Array<
- Pick & {
- options: Array>;
- variants: {
- nodes: Array<
- Pick & {
- price: Pick;
- }
- >;
- };
- }
- >;
- };
-};
-
-export type CategoryStorefrontFragment = Pick<
- StorefrontAPI.Collection,
- 'id' | 'title'
-> & {
- children?: StorefrontAPI.Maybe<{
- references?: StorefrontAPI.Maybe<{
- nodes: Array<
- Pick & {
- products: {
- nodes: Array<
- Pick
- >;
- };
- }
- >;
- }>;
- }>;
-};
-
-export type CategoriesStorefrontQueryVariables = StorefrontAPI.Exact<{
- country?: StorefrontAPI.InputMaybe;
- language?: StorefrontAPI.InputMaybe;
-}>;
-
-export type CategoriesStorefrontQuery = {
- collection?: StorefrontAPI.Maybe<
- Pick & {
- children?: StorefrontAPI.Maybe<{
- references?: StorefrontAPI.Maybe<{
- nodes: Array<
- Pick & {
- products: {
- nodes: Array<
- Pick<
- StorefrontAPI.Product,
- 'id' | 'title' | 'descriptionHtml'
- >
- >;
- };
- }
- >;
- }>;
- }>;
- }
- >;
-};
-
export type PredictiveArticleFragment = {__typename: 'Article'} & Pick<
StorefrontAPI.Article,
'id' | 'title' | 'handle' | 'trackingParameters'
@@ -3672,6 +3530,148 @@ export type PickMoreProductsQuery = {
};
};
+export type ProductSearchSimpleFragment = Pick<
+ StorefrontAPI.Product,
+ 'id' | 'title' | 'handle'
+>;
+
+export type ProductSearchQueryQueryVariables = StorefrontAPI.Exact<{
+ collectionId: StorefrontAPI.Scalars['ID']['input'];
+ country?: StorefrontAPI.InputMaybe;
+ language?: StorefrontAPI.InputMaybe;
+ first?: StorefrontAPI.InputMaybe;
+}>;
+
+export type ProductSearchQueryQuery = {
+ collection?: StorefrontAPI.Maybe<{
+ products: {
+ nodes: Array>;
+ };
+ }>;
+};
+
+export type ProductVariantIdsQueryVariables = StorefrontAPI.Exact<{
+ country?: StorefrontAPI.InputMaybe;
+ language?: StorefrontAPI.InputMaybe;
+ variantId:
+ | Array
+ | StorefrontAPI.Scalars['ID']['input'];
+}>;
+
+export type ProductVariantIdsQuery = {
+ nodes: Array<
+ StorefrontAPI.Maybe<
+ Pick<
+ StorefrontAPI.ProductVariant,
+ 'availableForSale' | 'id' | 'sku' | 'title'
+ > & {
+ compareAtPrice?: StorefrontAPI.Maybe<
+ Pick
+ >;
+ image?: StorefrontAPI.Maybe<
+ {__typename: 'Image'} & Pick<
+ StorefrontAPI.Image,
+ 'id' | 'url' | 'altText' | 'width' | 'height'
+ >
+ >;
+ price: Pick;
+ product: Pick;
+ selectedOptions: Array<
+ Pick
+ >;
+ unitPrice?: StorefrontAPI.Maybe<
+ Pick
+ >;
+ }
+ >
+ >;
+};
+
+export type ServicesOptionsTagProductFragment = Pick<
+ StorefrontAPI.Product,
+ 'id' | 'handle' | 'title'
+> & {
+ options: Array>;
+ variants: {
+ nodes: Array<
+ Pick & {
+ price: Pick;
+ }
+ >;
+ };
+};
+
+export type ServicesOptionsTagOptionsQueryQueryVariables = StorefrontAPI.Exact<{
+ country?: StorefrontAPI.InputMaybe;
+ language?: StorefrontAPI.InputMaybe;
+ query: StorefrontAPI.Scalars['String']['input'];
+ first?: StorefrontAPI.InputMaybe;
+}>;
+
+export type ServicesOptionsTagOptionsQueryQuery = {
+ products: {
+ nodes: Array<
+ Pick & {
+ options: Array>;
+ variants: {
+ nodes: Array<
+ Pick & {
+ price: Pick;
+ }
+ >;
+ };
+ }
+ >;
+ };
+};
+
+export type CategoryStorefrontFragment = Pick<
+ StorefrontAPI.Collection,
+ 'id' | 'title'
+> & {
+ children?: StorefrontAPI.Maybe<{
+ references?: StorefrontAPI.Maybe<{
+ nodes: Array<
+ Pick & {
+ products: {
+ nodes: Array<
+ Pick
+ >;
+ };
+ }
+ >;
+ }>;
+ }>;
+};
+
+export type CategoriesStorefrontQueryVariables = StorefrontAPI.Exact<{
+ country?: StorefrontAPI.InputMaybe;
+ language?: StorefrontAPI.InputMaybe;
+}>;
+
+export type CategoriesStorefrontQuery = {
+ collection?: StorefrontAPI.Maybe<
+ Pick & {
+ children?: StorefrontAPI.Maybe<{
+ references?: StorefrontAPI.Maybe<{
+ nodes: Array<
+ Pick & {
+ products: {
+ nodes: Array<
+ Pick<
+ StorefrontAPI.Product,
+ 'id' | 'title' | 'descriptionHtml'
+ >
+ >;
+ };
+ }
+ >;
+ }>;
+ }>;
+ }
+ >;
+};
+
export type CategoriesCollectionProductUserFragment = Pick<
StorefrontAPI.Metaobject,
'id'
@@ -5990,22 +5990,6 @@ interface GeneratedQueryTypes {
return: RecommendedTreatmentsQuery;
variables: RecommendedTreatmentsQueryVariables;
};
- '#graphql\n #graphql\n fragment ProductSearchSimple on Product {\n id\n title\n handle\n }\n\n query ProductSearchQuery(\n $collectionId: ID!\n $country: CountryCode\n $language: LanguageCode\n $first: Int\n ) @inContext(country: $country, language: $language) {\n collection(id: $collectionId) {\n products(first: $first) {\n nodes {\n ...ProductSearchSimple\n }\n }\n }\n }\n': {
- return: ProductSearchQueryQuery;
- variables: ProductSearchQueryQueryVariables;
- };
- '#graphql\n query ProductVariantIds(\n $country: CountryCode\n $language: LanguageCode\n $variantId: [ID!]!\n ) @inContext(country: $country, language: $language) {\n nodes(ids: $variantId){\n ...on ProductVariant{\n ...ProductVariant\n }\n }\n }\n #graphql\n fragment ProductVariant on ProductVariant {\n availableForSale\n compareAtPrice {\n amount\n currencyCode\n }\n id\n image {\n __typename\n id\n url\n altText\n width\n height\n }\n price {\n amount\n currencyCode\n }\n product {\n title\n handle\n }\n selectedOptions {\n name\n value\n }\n sku\n title\n unitPrice {\n amount\n currencyCode\n }\n }\n\n': {
- return: ProductVariantIdsQuery;
- variables: ProductVariantIdsQueryVariables;
- };
- '#graphql\n #graphql\n fragment MoneyProductItem on MoneyV2 {\n amount\n currencyCode\n }\n\n fragment ServicesOptionsTagProduct on Product {\n id\n handle\n title\n options {\n name\n values\n }\n variants(first: 5) {\n nodes {\n id\n title\n price {\n ...MoneyProductItem\n }\n }\n }\n }\n\n query ServicesOptionsTagOptionsQuery(\n $country: CountryCode\n $language: LanguageCode\n $query: String!\n $first: Int\n ) @inContext(country: $country, language: $language) {\n products(first: $first, query: $query) {\n nodes {\n ...ServicesOptionsTagProduct\n }\n }\n }\n': {
- return: ServicesOptionsTagOptionsQueryQuery;
- variables: ServicesOptionsTagOptionsQueryQueryVariables;
- };
- '#graphql\n #graphql\n fragment CategoryStorefront on Collection {\n id\n title\n children: metafield(key: "children", namespace: "booking") {\n references(first: 20) {\n nodes {\n ... on Collection {\n id\n title\n products(first: 30) {\n nodes {\n id\n title\n descriptionHtml\n }\n }\n }\n }\n }\n }\n }\n\n query CategoriesStorefront(\n $country: CountryCode\n $language: LanguageCode\n ) @inContext(country: $country, language: $language) {\n collection(handle: "alle-behandlinger") {\n ...CategoryStorefront\n }\n }\n': {
- return: CategoriesStorefrontQuery;
- variables: CategoriesStorefrontQueryVariables;
- };
'#graphql\n fragment PredictiveArticle on Article {\n __typename\n id\n title\n handle\n image {\n url\n altText\n width\n height\n }\n trackingParameters\n }\n fragment PredictiveCollection on Collection {\n __typename\n id\n title\n handle\n image {\n url\n altText\n width\n height\n }\n trackingParameters\n }\n fragment PredictivePage on Page {\n __typename\n id\n title\n handle\n trackingParameters\n }\n fragment PredictiveProduct on Product {\n __typename\n id\n title\n handle\n trackingParameters\n variants(first: 1) {\n nodes {\n id\n image {\n url\n altText\n width\n height\n }\n price {\n amount\n currencyCode\n }\n }\n }\n }\n fragment PredictiveQuery on SearchQuerySuggestion {\n __typename\n text\n styledText\n trackingParameters\n }\n query predictiveSearch(\n $country: CountryCode\n $language: LanguageCode\n $limit: Int!\n $limitScope: PredictiveSearchLimitScope!\n $searchTerm: String!\n $types: [PredictiveSearchType!]\n ) @inContext(country: $country, language: $language) {\n predictiveSearch(\n limit: $limit,\n limitScope: $limitScope,\n query: $searchTerm,\n types: $types,\n ) {\n articles {\n ...PredictiveArticle\n }\n collections {\n ...PredictiveCollection\n }\n pages {\n ...PredictivePage\n }\n products {\n ...PredictiveProduct\n }\n queries {\n ...PredictiveQuery\n }\n }\n }\n': {
return: PredictiveSearchQuery;
variables: PredictiveSearchQueryVariables;
@@ -6030,6 +6014,22 @@ interface GeneratedQueryTypes {
return: PickMoreProductsQuery;
variables: PickMoreProductsQueryVariables;
};
+ '#graphql\n #graphql\n fragment ProductSearchSimple on Product {\n id\n title\n handle\n }\n\n query ProductSearchQuery(\n $collectionId: ID!\n $country: CountryCode\n $language: LanguageCode\n $first: Int\n ) @inContext(country: $country, language: $language) {\n collection(id: $collectionId) {\n products(first: $first) {\n nodes {\n ...ProductSearchSimple\n }\n }\n }\n }\n': {
+ return: ProductSearchQueryQuery;
+ variables: ProductSearchQueryQueryVariables;
+ };
+ '#graphql\n query ProductVariantIds(\n $country: CountryCode\n $language: LanguageCode\n $variantId: [ID!]!\n ) @inContext(country: $country, language: $language) {\n nodes(ids: $variantId){\n ...on ProductVariant{\n ...ProductVariant\n }\n }\n }\n #graphql\n fragment ProductVariant on ProductVariant {\n availableForSale\n compareAtPrice {\n amount\n currencyCode\n }\n id\n image {\n __typename\n id\n url\n altText\n width\n height\n }\n price {\n amount\n currencyCode\n }\n product {\n title\n handle\n }\n selectedOptions {\n name\n value\n }\n sku\n title\n unitPrice {\n amount\n currencyCode\n }\n }\n\n': {
+ return: ProductVariantIdsQuery;
+ variables: ProductVariantIdsQueryVariables;
+ };
+ '#graphql\n #graphql\n fragment MoneyProductItem on MoneyV2 {\n amount\n currencyCode\n }\n\n fragment ServicesOptionsTagProduct on Product {\n id\n handle\n title\n options {\n name\n values\n }\n variants(first: 5) {\n nodes {\n id\n title\n price {\n ...MoneyProductItem\n }\n }\n }\n }\n\n query ServicesOptionsTagOptionsQuery(\n $country: CountryCode\n $language: LanguageCode\n $query: String!\n $first: Int\n ) @inContext(country: $country, language: $language) {\n products(first: $first, query: $query) {\n nodes {\n ...ServicesOptionsTagProduct\n }\n }\n }\n': {
+ return: ServicesOptionsTagOptionsQueryQuery;
+ variables: ServicesOptionsTagOptionsQueryQueryVariables;
+ };
+ '#graphql\n #graphql\n fragment CategoryStorefront on Collection {\n id\n title\n children: metafield(key: "children", namespace: "booking") {\n references(first: 20) {\n nodes {\n ... on Collection {\n id\n title\n products(first: 30) {\n nodes {\n id\n title\n descriptionHtml\n }\n }\n }\n }\n }\n }\n }\n\n query CategoriesStorefront(\n $country: CountryCode\n $language: LanguageCode\n ) @inContext(country: $country, language: $language) {\n collection(handle: "alle-behandlinger") {\n ...CategoryStorefront\n }\n }\n': {
+ return: CategoriesStorefrontQuery;
+ variables: CategoriesStorefrontQueryVariables;
+ };
'#graphql\n #graphql\n #graphql\n #graphql\n fragment CategoriesCollectionProductUser on Metaobject {\n id\n image: field(key: "image") {\n reference {\n ... on MediaImage {\n image {\n width\n height\n url(transform: { maxHeight: 100, maxWidth: 100, crop: CENTER })\n }\n }\n }\n }\n }\n\n\n fragment CategoriesCollectionProduct on Product {\n id\n user: metafield(key: "user", namespace: "booking") {\n reference {\n ...CategoriesCollectionProductUser\n }\n }\n }\n\n #graphql\n fragment CategoriesCollectionFilter on Filter {\n id\n label\n values {\n count\n }\n }\n\n\n fragment CategoriesCollection on Product {\n id\n title\n descriptionHtml\n description\n productType\n handle\n vendor\n featuredImage {\n id\n altText\n url(transform: { maxHeight: 250, maxWidth: 250, crop: CENTER })\n width\n height\n }\n collection: metafield(key: "collection", namespace: "system") {\n reference {\n ... on Collection {\n products(first: 3, sortKey: RELEVANCE, filters: [{productMetafield: {namespace: "system", key: "default", value: "true"}}, {productMetafield: {namespace: "booking", key: "hide_from_profile", value: "false"}}, {productMetafield: {namespace: "system", key: "active",value: "true"}}]) {\n filters {\n ...CategoriesCollectionFilter\n }\n nodes {\n ...CategoriesCollectionProduct\n }\n }\n }\n }\n }\n }\n\n query categoriesCollection(\n $handle: String!\n $country: CountryCode\n $language: LanguageCode\n $first: Int\n $last: Int\n $startCursor: String\n $endCursor: String\n ) @inContext(country: $country, language: $language) {\n collection(handle: $handle) {\n id\n handle\n title\n description\n products(\n first: $first,\n last: $last,\n before: $startCursor,\n after: $endCursor,\n sortKey: TITLE\n ) {\n nodes {\n ...CategoriesCollection\n }\n pageInfo {\n hasPreviousPage\n hasNextPage\n endCursor\n startCursor\n }\n }\n }\n }\n': {
return: CategoriesCollectionQuery;
variables: CategoriesCollectionQueryVariables;