diff --git a/app/home/(user)/(dashboard)/booking/page.tsx b/app/home/(user)/(dashboard)/booking/page.tsx new file mode 100644 index 0000000..32b2058 --- /dev/null +++ b/app/home/(user)/(dashboard)/booking/page.tsx @@ -0,0 +1,34 @@ +import { PageBody } from '@kit/ui/page'; +import { Trans } from '@kit/ui/trans'; + +import { createI18nServerInstance } from '~/lib/i18n/i18n.server'; +import { withI18n } from '~/lib/i18n/with-i18n'; + +import { HomeLayoutPageHeader } from '../../_components/home-page-header'; +import OrderCards from '../../_components/order-cards'; + +export const generateMetadata = async () => { + const i18n = await createI18nServerInstance(); + const title = i18n.t('booking:title'); + + return { + title, + }; +}; + +function BookingPage() { + return ( + <> + } + description={} + /> + + + + + + ); +} + +export default withI18n(BookingPage); diff --git a/app/home/(user)/(dashboard)/order-analysis-package/page.tsx b/app/home/(user)/(dashboard)/order-analysis-package/page.tsx new file mode 100644 index 0000000..7ac0ed4 --- /dev/null +++ b/app/home/(user)/(dashboard)/order-analysis-package/page.tsx @@ -0,0 +1,42 @@ +import { Scale } from 'lucide-react'; + +import { createI18nServerInstance } from '~/lib/i18n/i18n.server'; +import { withI18n } from '~/lib/i18n/with-i18n'; +import { Button } from '@kit/ui/button'; +import SelectAnalysisPackages from '@/components/select-analysis-packages'; +import { PageBody } from '@kit/ui/page'; +import { Trans } from '@kit/ui/trans'; + +import ComparePackagesModal from '../../_components/compare-packages-modal'; + +export const generateMetadata = async () => { + const i18n = await createI18nServerInstance(); + const title = i18n.t('order-analysis-package:title'); + + return { + title, + }; +}; + +async function OrderAnalysisPackagePage() { + return ( + +
+

+ +

+ + + + + } + /> +
+ +
+ ); +} + +export default withI18n(OrderAnalysisPackagePage); diff --git a/app/home/(user)/(dashboard)/page.tsx b/app/home/(user)/(dashboard)/page.tsx index 2aabc91..75b3d20 100644 --- a/app/home/(user)/(dashboard)/page.tsx +++ b/app/home/(user)/(dashboard)/page.tsx @@ -1,15 +1,13 @@ -import { use } from 'react'; - -import { PageBody } from '@kit/ui/page'; -import { Trans } from '@kit/ui/trans'; +import { redirect } from 'next/navigation'; import { createI18nServerInstance } from '~/lib/i18n/i18n.server'; import { withI18n } from '~/lib/i18n/with-i18n'; +import { PageBody, PageHeader } from '@kit/ui/page'; +import { Trans } from '@kit/ui/trans'; +import { toTitleCase } from '@/lib/utils'; import Dashboard from '../_components/dashboard'; -// local imports -import { HomeLayoutPageHeader } from '../_components/home-page-header'; -import { loadUserWorkspace } from '../_lib/server/load-user-workspace'; +import { loadCurrentUserAccount } from '../_lib/server/load-user-account'; export const generateMetadata = async () => { const i18n = await createI18nServerInstance(); @@ -20,15 +18,24 @@ export const generateMetadata = async () => { }; }; -function UserHomePage() { - const { tempVisibleAccounts } = use(loadUserWorkspace()); +async function UserHomePage() { + const account = await loadCurrentUserAccount(); + if (!account) { + redirect('/'); + } + return ( <> - } - description={<>} + + + {account.name ? `, ${toTitleCase(account.name)}` : ''} + + } + description={ + + } /> - diff --git a/app/home/(user)/_components/compare-packages-modal.tsx b/app/home/(user)/_components/compare-packages-modal.tsx index d830b45..5f581e7 100644 --- a/app/home/(user)/_components/compare-packages-modal.tsx +++ b/app/home/(user)/_components/compare-packages-modal.tsx @@ -18,12 +18,10 @@ import { TableHeader, TableRow, } from '@kit/ui/table'; - import { createI18nServerInstance } from '~/lib/i18n/i18n.server'; import { withI18n } from '~/lib/i18n/with-i18n'; - -import { PackageHeader } from '../../../../components/package-header'; -import { InfoTooltip } from '../../../../components/ui/info-tooltip'; +import { PackageHeader } from '@/components/package-header'; +import { InfoTooltip } from '@/components/ui/info-tooltip'; const dummyCards = [ { diff --git a/app/home/(user)/_components/dashboard.tsx b/app/home/(user)/_components/dashboard.tsx index f6cc187..3351444 100644 --- a/app/home/(user)/_components/dashboard.tsx +++ b/app/home/(user)/_components/dashboard.tsx @@ -1,7 +1,7 @@ 'use client'; +import Link from 'next/link'; import { InfoTooltip } from '@/components/ui/info-tooltip'; -import { toTitleCase } from '@/lib/utils'; import { BlendingModeIcon, RulerHorizontalIcon } from '@radix-ui/react-icons'; import { Activity, @@ -15,8 +15,6 @@ import { User, } from 'lucide-react'; -import { usePersonalAccountData } from '@kit/accounts/hooks/use-personal-account-data'; -import { useUserWorkspace } from '@kit/accounts/hooks/use-user-workspace'; import { Button } from '@kit/ui/button'; import { Card, @@ -26,7 +24,6 @@ import { CardHeader, CardProps, } from '@kit/ui/card'; -import { PageDescription } from '@kit/ui/page'; import { Trans } from '@kit/ui/trans'; import { cn } from '@kit/ui/utils'; @@ -107,6 +104,7 @@ const dummyRecommendations = [ tooltipContent: 'Selgitus', price: '20,00 €', buttonText: 'Telli', + href: '/home/booking', }, { icon: , @@ -115,6 +113,7 @@ const dummyRecommendations = [ tooltipContent: 'Selgitus', description: 'LDL-Kolesterool', buttonText: 'Broneeri', + href: '/home/booking', }, { icon: , @@ -124,24 +123,13 @@ const dummyRecommendations = [ description: 'Score-Risk 2', price: '20,00 €', buttonText: 'Telli', + href: '/home/booking', }, ]; export default function Dashboard() { - const userWorkspace = useUserWorkspace(); - const account = usePersonalAccountData(userWorkspace.user.id); - return ( <> -
-

- - {account?.data?.name ? `, ${toTitleCase(account.data.name)}` : ''} -

- - : - -
{dummyCards.map( ({ @@ -196,6 +184,7 @@ export default function Dashboard() { tooltipContent, price, buttonText, + href, }, index, ) => { @@ -222,9 +211,17 @@ export default function Dashboard() {

{price}

- + {href ? ( + + + + ) : ( + + )}
); diff --git a/app/home/(user)/_components/home-page-header.tsx b/app/home/(user)/_components/home-page-header.tsx index 209a4f4..da64f7f 100644 --- a/app/home/(user)/_components/home-page-header.tsx +++ b/app/home/(user)/_components/home-page-header.tsx @@ -7,6 +7,6 @@ export function HomeLayoutPageHeader( }>, ) { return ( - {props.children} + {props.children} ); } diff --git a/app/home/(user)/_components/order-cards.tsx b/app/home/(user)/_components/order-cards.tsx new file mode 100644 index 0000000..bf95ace --- /dev/null +++ b/app/home/(user)/_components/order-cards.tsx @@ -0,0 +1,77 @@ +"use client"; + +import { ChevronRight, HeartPulse } from 'lucide-react'; +import Link from 'next/link'; + +import { Button } from '@kit/ui/button'; +import { + Card, + CardHeader, + CardDescription, + CardProps, + CardFooter, +} from '@kit/ui/card'; +import { Trans } from '@kit/ui/trans'; +import { cn } from '@/lib/utils'; + +const dummyCards = [ + { + title: 'booking:analysisPackages.title', + description: 'booking:analysisPackages.description', + descriptionColor: 'text-primary', + icon: ( + + + + ), + cardVariant: 'gradient-success' as CardProps['variant'], + iconBg: 'bg-warning', + }, +]; + +export default function OrderCards() { + return ( +
+ {dummyCards.map(({ + title, + description, + icon, + cardVariant, + descriptionColor, + iconBg, + }) => ( + + +
+ {icon} +
+
+ +
+ +
+
+ +
+ + + +
+
+ ))} +
+ ); +} diff --git a/app/home/(user)/_lib/server/load-user-account.ts b/app/home/(user)/_lib/server/load-user-account.ts index de88993..471def2 100644 --- a/app/home/(user)/_lib/server/load-user-account.ts +++ b/app/home/(user)/_lib/server/load-user-account.ts @@ -2,6 +2,7 @@ import { cache } from 'react'; import { createAccountsApi } from '@kit/accounts/api'; import { getSupabaseServerClient } from '@kit/supabase/server-client'; +import { requireUserInServerComponent } from '@/lib/server/require-user-in-server-component'; export type UserAccount = Awaited>; @@ -13,6 +14,13 @@ export type UserAccount = Awaited>; */ export const loadUserAccount = cache(accountLoader); +export async function loadCurrentUserAccount() { + const user = await requireUserInServerComponent(); + return user?.identities?.[0]?.id + ? await loadUserAccount(user?.identities?.[0]?.id) + : null; +} + async function accountLoader(accountId: string) { const client = getSupabaseServerClient(); const api = createAccountsApi(client); diff --git a/app/home/layout.tsx b/app/home/layout.tsx index 08a2b19..680b15d 100644 --- a/app/home/layout.tsx +++ b/app/home/layout.tsx @@ -1,6 +1,6 @@ -import { requireUserInServerComponent } from '../../lib/server/require-user-in-server-component'; +import { requireUserInServerComponent } from '@/lib/server/require-user-in-server-component'; import ConsentDialog from './(user)/_components/consent-dialog'; -import { loadUserAccount } from './(user)/_lib/server/load-user-account'; +import { loadCurrentUserAccount } from './(user)/_lib/server/load-user-account'; export default async function HomeLayout({ children, @@ -8,9 +8,7 @@ export default async function HomeLayout({ children: React.ReactNode; }) { const user = await requireUserInServerComponent(); - const account = user?.identities?.[0]?.id - ? await loadUserAccount(user?.identities?.[0]?.id) - : null; + const account = await loadCurrentUserAccount() if (account && account?.has_consent_anonymized_company_statistics === null) { return ( diff --git a/app/select-package/page.tsx b/app/select-package/page.tsx index 6e1b52a..e4de4bb 100644 --- a/app/select-package/page.tsx +++ b/app/select-package/page.tsx @@ -1,24 +1,16 @@ -import Image from 'next/image'; import Link from 'next/link'; import { CaretRightIcon } from '@radix-ui/react-icons'; import { Scale } from 'lucide-react'; +import { Trans } from '@kit/ui/trans'; import { Button } from '@kit/ui/button'; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, -} from '@kit/ui/card'; import { createI18nServerInstance } from '~/lib/i18n/i18n.server'; import { withI18n } from '~/lib/i18n/with-i18n'; +import SelectAnalysisPackages from '@/components/select-analysis-packages'; import { MedReportLogo } from '../../components/med-report-logo'; -import { PackageHeader } from '../../components/package-header'; -import { ButtonTooltip } from '../../components/ui/button-tooltip'; import pathsConfig from '../../config/paths.config'; import ComparePackagesModal from '../home/(user)/_components/compare-packages-modal'; @@ -30,100 +22,30 @@ export const generateMetadata = async () => { }; }; -const dummyCards = [ - { - titleKey: 'product:standard.label', - price: 40, - nrOfAnalyses: 4, - tagColor: 'bg-cyan', - descriptionKey: 'marketing:standard.description', - }, - { - titleKey: 'product:standardPlus.label', - price: 85, - nrOfAnalyses: 10, - - tagColor: 'bg-warning', - descriptionKey: 'product:standardPlus.description', - }, - { - titleKey: 'product:premium.label', - price: 140, - nrOfAnalyses: '12+', - - tagColor: 'bg-purple', - descriptionKey: 'product:premium.description', - }, -]; - async function SelectPackagePage() { - const { t, language } = await createI18nServerInstance(); - return (
-

{t('marketing:selectPackage')}

+

+ +

- {t('marketing:comparePackages')} + } />
-
- {dummyCards.map( - ( - { titleKey, price, nrOfAnalyses, tagColor, descriptionKey }, - index, - ) => { - return ( - - - - background - - - - {t(descriptionKey)} - - - - - - ); - }, - )} -
-
- - - -
-
-
+ + + +
); } diff --git a/components/select-analysis-packages.tsx b/components/select-analysis-packages.tsx new file mode 100644 index 0000000..b5149fe --- /dev/null +++ b/components/select-analysis-packages.tsx @@ -0,0 +1,108 @@ +'use client'; + +import Image from 'next/image'; +import { useTranslation } from 'react-i18next'; + +import { Button } from '@kit/ui/button'; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, +} from '@kit/ui/card'; +import { Trans } from '@kit/ui/trans'; + +import { PackageHeader } from './package-header'; +import { ButtonTooltip } from './ui/button-tooltip'; + +export interface IAnalysisPackage { + titleKey: string; + price: number; + nrOfAnalyses: number | string; + tagColor: string; + descriptionKey: string; +} + +const analysisPackages = [ + { + titleKey: 'product:standard.label', + price: 40, + nrOfAnalyses: 4, + tagColor: 'bg-cyan', + descriptionKey: 'marketing:standard.description', + }, + { + titleKey: 'product:standardPlus.label', + price: 85, + nrOfAnalyses: 10, + + tagColor: 'bg-warning', + descriptionKey: 'product:standardPlus.description', + }, + { + titleKey: 'product:premium.label', + price: 140, + nrOfAnalyses: '12+', + + tagColor: 'bg-purple', + descriptionKey: 'product:premium.description', + }, +] satisfies IAnalysisPackage[]; + +export default function SelectAnalysisPackages() { + const { + t, + i18n: { language }, + } = useTranslation(); + + return ( +
+ {analysisPackages.length > 0 ? analysisPackages.map( + ( + { titleKey, price, nrOfAnalyses, tagColor, descriptionKey }, + index, + ) => { + return ( + + + + background + + + + + + + + + + + + ); + }, + ) : ( +

+ +

+ )} +
+ ); +} diff --git a/config/paths.config.ts b/config/paths.config.ts index e9c54ca..0a9ff76 100644 --- a/config/paths.config.ts +++ b/config/paths.config.ts @@ -57,11 +57,11 @@ const pathsConfig = PathsSchema.parse({ accountBillingReturn: `/home/[account]/billing/return`, joinTeam: '/join', selectPackage: '/select-package', + booking: '/home/booking', + orderAnalysisPackage: '/home/order-analysis-package', // these routes are added as placeholders and can be changed when the pages are added - booking: '/booking', myOrders: '/my-orders', analysisResults: '/home/analysis-results', - orderAnalysisPackage: '/order-analysis-package', orderAnalysis: '/order-analysis', orderHealthAnalysis: '/order-health-analysis', }, diff --git a/lib/i18n/i18n.settings.ts b/lib/i18n/i18n.settings.ts index 730259e..22b4768 100644 --- a/lib/i18n/i18n.settings.ts +++ b/lib/i18n/i18n.settings.ts @@ -34,6 +34,8 @@ export const defaultI18nNamespaces = [ 'marketing', 'dashboard', 'product', + 'booking', + 'order-analysis-package', ]; /** diff --git a/packages/features/accounts/src/components/personal-account-dropdown.tsx b/packages/features/accounts/src/components/personal-account-dropdown.tsx index 7648a3f..fd2bab8 100644 --- a/packages/features/accounts/src/components/personal-account-dropdown.tsx +++ b/packages/features/accounts/src/components/personal-account-dropdown.tsx @@ -26,9 +26,10 @@ import { SubMenuModeToggle } from '@kit/ui/mode-toggle'; import { ProfileAvatar } from '@kit/ui/profile-avatar'; import { Trans } from '@kit/ui/trans'; import { cn } from '@kit/ui/utils'; - + import { usePersonalAccountData } from '../hooks/use-personal-account-data'; import { Avatar, AvatarFallback, AvatarImage } from '@kit/ui/avatar'; +import { toTitleCase } from '~/lib/utils'; const PERSONAL_ACCOUNT_SLUG = 'personal'; @@ -124,7 +125,7 @@ export function PersonalAccountDropdown({ data-test={'account-dropdown-display-name'} className={'truncate text-sm'} > - {displayName} + {toTitleCase(displayName)} diff --git a/packages/features/accounts/tsconfig.json b/packages/features/accounts/tsconfig.json index 9a53360..8d5bae9 100644 --- a/packages/features/accounts/tsconfig.json +++ b/packages/features/accounts/tsconfig.json @@ -1,7 +1,10 @@ { "extends": "@kit/tsconfig/base.json", "compilerOptions": { - "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" + "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json", + "paths": { + "~/lib/utils": ["../../../lib/utils.ts"] + } }, "include": ["*.ts", "*.tsx", "src"], "exclude": ["node_modules"] diff --git a/packages/features/auth/src/components/password-sign-up-form.tsx b/packages/features/auth/src/components/password-sign-up-form.tsx index 1b29b97..f7d8de5 100644 --- a/packages/features/auth/src/components/password-sign-up-form.tsx +++ b/packages/features/auth/src/components/password-sign-up-form.tsx @@ -76,7 +76,6 @@ export function PasswordSignUpForm({ data-test={'personal-code-input'} required type="text" - placeholder={t('personalCodePlaceholder')} {...field} /> diff --git a/packages/ui/src/makerkit/page.tsx b/packages/ui/src/makerkit/page.tsx index 9f27a50..ec5aa48 100644 --- a/packages/ui/src/makerkit/page.tsx +++ b/packages/ui/src/makerkit/page.tsx @@ -129,13 +129,13 @@ export function PageDescription(props: React.PropsWithChildren) { export function PageTitle(props: React.PropsWithChildren) { return ( -

{props.children} -

+ ); } @@ -163,6 +163,10 @@ export function PageHeader({ )} >
+ + {title} + +
{displaySidebarTrigger ? ( @@ -179,10 +183,6 @@ export function PageHeader({ {description}
- - - {title} -
{children} diff --git a/public/locales/en/booking.json b/public/locales/en/booking.json new file mode 100644 index 0000000..f4ef7c2 --- /dev/null +++ b/public/locales/en/booking.json @@ -0,0 +1,8 @@ +{ + "title": "Select service", + "description": "Select the appropriate service or package according to your health needs or goals.", + "analysisPackages": { + "title": "Analysis packages", + "description": "Get to know the personal analysis packages and order" + } +} \ No newline at end of file diff --git a/public/locales/en/marketing.json b/public/locales/en/marketing.json index a89e086..aeeb1b4 100644 --- a/public/locales/en/marketing.json +++ b/public/locales/en/marketing.json @@ -37,8 +37,5 @@ "footerDescription": "Here you can add a description about your company or product", "copyright": "© Copyright {{year}} {{product}}. All Rights Reserved.", "heroSubtitle": "A simple, convenient, and quick overview of your health condition", - "selectPackage": "Select package", - "selectThisPackage": "Select this package", - "comparePackages": "Compare packages", "notInterestedInAudit": "Currently not interested in a health audit" } \ No newline at end of file diff --git a/public/locales/en/order-analysis-package.json b/public/locales/en/order-analysis-package.json new file mode 100644 index 0000000..9502bf1 --- /dev/null +++ b/public/locales/en/order-analysis-package.json @@ -0,0 +1,7 @@ +{ + "title": "Select analysis package", + "noPackagesAvailable": "No packages available", + "selectThisPackage": "Select this package", + "selectPackage": "Select package", + "comparePackages": "Compare packages" +} \ No newline at end of file diff --git a/public/locales/et/booking.json b/public/locales/et/booking.json new file mode 100644 index 0000000..17554de --- /dev/null +++ b/public/locales/et/booking.json @@ -0,0 +1,8 @@ +{ + "title": "Vali teenus", + "description": "Vali sobiv teenus või pakett vastavalt oma tervisemurele või -eesmärgile.", + "analysisPackages": { + "title": "Analüüside paketid", + "description": "Tutvu personaalsete analüüsi pakettidega ja telli" + } +} \ No newline at end of file diff --git a/public/locales/et/common.json b/public/locales/et/common.json index cd99164..05008e4 100644 --- a/public/locales/et/common.json +++ b/public/locales/et/common.json @@ -61,7 +61,7 @@ "search": "Otsi{{end}}", "myActions": "Minu toimingud", "healthPackageComparison": { - "label": "Tervisepakketide võrdlus", + "label": "Tervisepakettide võrdlus", "description": "Alljärgnevalt on antud eelinfo (sugu, vanus ja kehamassiindeksi) põhjal tehtud personalne terviseauditi valik. Tabelis on võimalik soovitatud terviseuuringute paketile lisada üksikuid uuringuid juurde." }, "routes": { diff --git a/public/locales/et/marketing.json b/public/locales/et/marketing.json index 4faec68..0f5f9c1 100644 --- a/public/locales/et/marketing.json +++ b/public/locales/et/marketing.json @@ -37,8 +37,5 @@ "footerDescription": "Here you can add a description about your company or product", "copyright": "© Copyright {{year}} {{product}}. All Rights Reserved.", "heroSubtitle": "Lihtne, mugav ja kiire ülevaade oma tervisest", - "selectPackage": "Vali pakett", - "selectThisPackage": "Vali see pakett", - "comparePackages": "Võrdle pakette", "notInterestedInAudit": "Ei soovi hetkel terviseauditit" } \ No newline at end of file diff --git a/public/locales/et/order-analysis-package.json b/public/locales/et/order-analysis-package.json new file mode 100644 index 0000000..2c44087 --- /dev/null +++ b/public/locales/et/order-analysis-package.json @@ -0,0 +1,7 @@ +{ + "title": "Vali analüüsi pakett", + "noPackagesAvailable": "Teenuste loetelu ei leitud, proovi hiljem uuesti", + "selectThisPackage": "Vali see pakett", + "selectPackage": "Vali pakett", + "comparePackages": "Võrdle pakette" +} \ No newline at end of file diff --git a/public/locales/ru/booking.json b/public/locales/ru/booking.json new file mode 100644 index 0000000..f4ef7c2 --- /dev/null +++ b/public/locales/ru/booking.json @@ -0,0 +1,8 @@ +{ + "title": "Select service", + "description": "Select the appropriate service or package according to your health needs or goals.", + "analysisPackages": { + "title": "Analysis packages", + "description": "Get to know the personal analysis packages and order" + } +} \ No newline at end of file diff --git a/public/locales/ru/marketing.json b/public/locales/ru/marketing.json index a89e086..aeeb1b4 100644 --- a/public/locales/ru/marketing.json +++ b/public/locales/ru/marketing.json @@ -37,8 +37,5 @@ "footerDescription": "Here you can add a description about your company or product", "copyright": "© Copyright {{year}} {{product}}. All Rights Reserved.", "heroSubtitle": "A simple, convenient, and quick overview of your health condition", - "selectPackage": "Select package", - "selectThisPackage": "Select this package", - "comparePackages": "Compare packages", "notInterestedInAudit": "Currently not interested in a health audit" } \ No newline at end of file diff --git a/public/locales/ru/order-analysis-package.json b/public/locales/ru/order-analysis-package.json new file mode 100644 index 0000000..9502bf1 --- /dev/null +++ b/public/locales/ru/order-analysis-package.json @@ -0,0 +1,7 @@ +{ + "title": "Select analysis package", + "noPackagesAvailable": "No packages available", + "selectThisPackage": "Select this package", + "selectPackage": "Select package", + "comparePackages": "Compare packages" +} \ No newline at end of file diff --git a/styles/globals.css b/styles/globals.css index 0ec1d7d..50b8740 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -89,4 +89,8 @@ .lucide { @apply size-4; } + + button { + cursor: pointer; + } }