Skip to content

Commit 8bf6780

Browse files
feat: added info notification about the demo version
1 parent 1b27eb9 commit 8bf6780

File tree

6 files changed

+127
-33
lines changed

6 files changed

+127
-33
lines changed

apps/frontend/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@
2121
"@o2s/api-harmonization": "*",
2222
"@o2s/ui": "*",
2323
"@prisma/client": "^6.3.1",
24+
"@types/js-cookie": "^3.0.6",
2425
"@vercel/analytics": "^1.5.0",
2526
"@vercel/speed-insights": "^1.2.0",
2627
"bcryptjs": "^2.4.3",
2728
"class-variance-authority": "^0.7.1",
2829
"dotenv-cli": "^8.0.0",
2930
"formik": "^2.4.6",
31+
"js-cookie": "^3.0.5",
3032
"jsonwebtoken": "^9.0.2",
3133
"markdown-to-jsx": "^7.7.3",
3234
"next": "15.2.1",

apps/frontend/src/app/[locale]/layout.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { SpeedInsights } from '@vercel/speed-insights/next';
33
import { SessionProvider } from 'next-auth/react';
44
import { setRequestLocale } from 'next-intl/server';
55
import { Inter } from 'next/font/google';
6-
import { headers } from 'next/headers';
6+
import { cookies, headers } from 'next/headers';
77
import { notFound } from 'next/navigation';
88
import React from 'react';
99

@@ -36,6 +36,8 @@ export default async function RootLayout({ children, params }: Props) {
3636
const headersList = await headers();
3737
const session = await auth();
3838

39+
const cookieStore = await cookies();
40+
3941
const { locale } = await params;
4042

4143
if (!routing.locales.includes(locale)) {
@@ -59,7 +61,10 @@ export default async function RootLayout({ children, params }: Props) {
5961
<SessionProvider key={session?.user?.id} session={session} refetchOnWindowFocus={false}>
6062
<GlobalProvider config={init} locale={locale}>
6163
<div className="flex flex-col min-h-dvh">
62-
<Header headerData={init.common.header} />
64+
<Header
65+
headerData={init.common.header}
66+
isDemoHidden={cookieStore.get('demoHidden')?.value === 'true'}
67+
/>
6368

6469
<div className="flex flex-col grow">{children}</div>
6570

apps/frontend/src/components/Header/Header.tsx

Lines changed: 91 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
'use client';
22

3+
import Cookies from 'js-cookie';
4+
import { X } from 'lucide-react';
35
import { useSession } from 'next-auth/react';
6+
import { useLocale } from 'next-intl';
47
import Image from 'next/image';
5-
import React from 'react';
8+
import React, { useState } from 'react';
69

10+
import { Button } from '@o2s/ui/components/button';
11+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@o2s/ui/components/collapsible';
712
import { Link } from '@o2s/ui/components/link';
13+
import { Typography } from '@o2s/ui/components/typography';
814

915
import { Link as NextLink } from '@/i18n';
1016

@@ -17,10 +23,29 @@ import { MobileNavigation } from './MobileNavigation/MobileNavigation';
1723
import { NotificationInfo } from './NotificationInfo/NotificationInfo';
1824
import { UserInfo } from './UserInfo/UserInfo';
1925

20-
export const Header: React.FC<HeaderProps> = ({ headerData, children }) => {
26+
const MOCK: { [key: string]: { info: string; link: string } } = {
27+
en: {
28+
info: 'You are currently viewing a demo version, where parts of the app may not be fully ready yet. If you notice any issues or want to give us your feedback, you can',
29+
link: 'do it here',
30+
},
31+
de: {
32+
info: 'Sie sehen derzeit eine Demoversion, in der Teile der App möglicherweise noch nicht vollständig fertiggestellt sind. Wenn Sie Probleme bemerken oder uns Ihr Feedback geben möchten, können Sie',
33+
link: 'das hier tun',
34+
},
35+
pl: {
36+
info: 'Obecnie przeglądasz wersję demonstracyjną, gdzie niektóre części aplikacji mogą nie być jeszcze w pełni gotowe. Jeśli zauważysz jakieś problemy lub chcesz przekazać nam swoją opinię, możesz',
37+
link: 'zrobić to tutaj',
38+
},
39+
};
40+
41+
export const Header: React.FC<HeaderProps> = ({ headerData, isDemoHidden, children }) => {
2142
const session = useSession();
2243
const isSignedIn = session?.status === 'authenticated';
2344

45+
const locale = useLocale();
46+
47+
const [demoHidden, setDemoHidden] = useState(isDemoHidden);
48+
2449
const LogoSlot = (
2550
<Link asChild>
2651
<NextLink href="/" aria-label={headerData.logo?.name}>
@@ -60,32 +85,69 @@ export const Header: React.FC<HeaderProps> = ({ headerData, children }) => {
6085
isSignedIn && headerData.contextSwitcher && <ContextSwitcher context={headerData.contextSwitcher} />;
6186

6287
return (
63-
<header className="flex flex-col gap-4">
64-
<>
65-
<div className="md:block hidden">
66-
<DesktopNavigation
67-
logoSlot={LogoSlot}
68-
contextSlot={<ContextSwitchSlot />}
69-
localeSlot={<LocaleSlot />}
70-
notificationSlot={<NotificationSlot />}
71-
userSlot={<UserSlot />}
72-
items={headerData.items}
73-
/>
74-
</div>
75-
<div className="md:hidden">
76-
<MobileNavigation
77-
logoSlot={LogoSlot}
78-
contextSlot={<ContextSwitchSlot />}
79-
localeSlot={<LocaleSlot />}
80-
notificationSlot={<NotificationSlot />}
81-
userSlot={<UserSlot />}
82-
items={headerData.items}
83-
title={headerData.title}
84-
mobileMenuLabel={headerData.mobileMenuLabel}
85-
/>
86-
</div>
87-
</>
88-
{children}
89-
</header>
88+
<>
89+
<Collapsible
90+
open={!demoHidden}
91+
onOpenChange={() => {
92+
setDemoHidden(true);
93+
Cookies.set('demoHidden', 'true', { expires: 1 });
94+
}}
95+
>
96+
<CollapsibleContent defaultOpen={!demoHidden}>
97+
<div className="bg-primary text-primary-foreground">
98+
<div className="px-4 md:px-6 py-2 ml-auto mr-auto w-full md:max-w-7xl">
99+
<div className="flex gap-4 items-center justify-between">
100+
<Typography variant="small">
101+
{(MOCK[locale] || MOCK.en)!.info}{' '}
102+
<Link
103+
href="https://github.com/o2sdev/openselfservice/issues"
104+
target="_blank"
105+
className="text-primary-foreground underline"
106+
>
107+
{(MOCK[locale] || MOCK.en)!.link}
108+
</Link>
109+
.
110+
</Typography>
111+
112+
<CollapsibleTrigger asChild>
113+
<Button variant="ghost" size="sm" className="w-9 p-0 shrink-0">
114+
<X className="h-4 w-4" />
115+
<span className="sr-only">Close</span>
116+
</Button>
117+
</CollapsibleTrigger>
118+
</div>
119+
</div>
120+
</div>
121+
</CollapsibleContent>
122+
</Collapsible>
123+
124+
<header className="flex flex-col gap-4">
125+
<>
126+
<div className="md:block hidden">
127+
<DesktopNavigation
128+
logoSlot={LogoSlot}
129+
contextSlot={<ContextSwitchSlot />}
130+
localeSlot={<LocaleSlot />}
131+
notificationSlot={<NotificationSlot />}
132+
userSlot={<UserSlot />}
133+
items={headerData.items}
134+
/>
135+
</div>
136+
<div className="md:hidden">
137+
<MobileNavigation
138+
logoSlot={LogoSlot}
139+
contextSlot={<ContextSwitchSlot />}
140+
localeSlot={<LocaleSlot />}
141+
notificationSlot={<NotificationSlot />}
142+
userSlot={<UserSlot />}
143+
items={headerData.items}
144+
title={headerData.title}
145+
mobileMenuLabel={headerData.mobileMenuLabel}
146+
/>
147+
</div>
148+
</>
149+
{children}
150+
</header>
151+
</>
90152
);
91153
};

apps/frontend/src/components/Header/Header.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ import { CMS } from '@o2s/framework/modules';
44

55
export interface HeaderProps {
66
headerData: CMS.Model.Header.Header;
7+
isDemoHidden?: boolean;
78
children?: React.ReactNode;
89
}

package-lock.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/ui/src/components/collapsible.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
2+
import { cx } from 'class-variance-authority';
23
import * as React from 'react';
34

45
const Collapsible = CollapsiblePrimitive.Root;
56

67
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
78

8-
const CollapsibleContent = (props: React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.CollapsibleContent>) => (
9+
export interface CollapsibleContentProps
10+
extends React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.CollapsibleContent> {
11+
defaultOpen?: boolean;
12+
}
13+
14+
const CollapsibleContent = ({ defaultOpen, ...props }: CollapsibleContentProps) => (
915
<CollapsiblePrimitive.CollapsibleContent
10-
className="overflow-hidden transition-all data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down"
16+
className={cx(
17+
'overflow-hidden transition-all data-[state=closed]:animate-collapsible-up',
18+
!defaultOpen && 'data-[state=open]:animate-collapsible-down',
19+
)}
1120
{...props}
1221
/>
1322
);

0 commit comments

Comments
 (0)