Skip to content

Commit 85867d3

Browse files
AmbtenaarInFunctiernacken
authored andcommitted
pocje voor feature flags
1 parent 1aa6521 commit 85867d3

6 files changed

Lines changed: 338 additions & 22 deletions

File tree

package-lock.json

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

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"react": "^19.0.0",
3030
"react-dom": "^19.2.3",
3131
"tailwind-variants": "^1.0.0",
32-
"zod": "^4.3.5"
32+
"zod": "^4.3.5",
33+
"zustand": "^5.0.11"
3334
},
3435
"devDependencies": {
3536
"@eslint/eslintrc": "^3",

src/app/instellingen/page.tsx

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
"use client";
2+
import Card from "@/components/card";
3+
import {
4+
useFeatureFlagsStore,
5+
useHydratedFeatureFlags,
6+
type FeatureFlagKey,
7+
} from "@/stores/featureFlags";
8+
9+
const Page = () => {
10+
return (
11+
<>
12+
<h1 className="text-4xl">Instellingen</h1>
13+
<Card className="space-y-5">
14+
<h2 className="text-3xl">Beta instellingen</h2>
15+
<p>
16+
Hieronder kun je experimentele functionaliteiten in- en uitschakelen.
17+
Deze beta-functies zijn nog in ontwikkeling en kunnen nog veranderen.
18+
Door ze te activeren help je ons deze nieuwe mogelijkheden te testen
19+
en te verbeteren. Je kunt de functies op elk moment weer uitschakelen.
20+
</p>
21+
22+
<div className="space-y-5">
23+
<ToggleFeature
24+
featureLabel={"Mijn Zaken"}
25+
featureName="feature_MijnZaken"
26+
/>
27+
<ToggleFeature
28+
featureLabel={"Mijn Taken"}
29+
featureName="feature_MijnTaken"
30+
/>
31+
<ToggleFeature
32+
featureLabel={"Mijn Producten"}
33+
featureName="feature_MijnProducten"
34+
/>
35+
<ToggleFeature
36+
featureLabel={"RegelRecht"}
37+
featureName="feature_RegelRecht"
38+
/>
39+
</div>
40+
</Card>
41+
</>
42+
);
43+
};
44+
45+
const ToggleFeature = ({
46+
featureLabel,
47+
featureName,
48+
}: {
49+
featureLabel: string;
50+
featureName: FeatureFlagKey;
51+
}) => {
52+
const isHydrated = useHydratedFeatureFlags();
53+
const isToggled = useFeatureFlagsStore((s) => s.flags[featureName]);
54+
console.log(isToggled);
55+
const toggleFlag = useFeatureFlagsStore((s) => s.toggleFlag);
56+
57+
const handleToggle = () => toggleFlag(featureName);
58+
59+
if (!isHydrated) return null;
60+
61+
return (
62+
<div className="flex items-center gap-3">
63+
<label className="text-base font-medium">{featureLabel}</label>
64+
65+
<div
66+
className={`flex h-6 w-12 cursor-pointer items-center rounded-full border border-gray-300 shadow-2xl transition-all duration-100 ${
67+
isToggled ? "bg-blue-100" : "bg-gray-100"
68+
}`}
69+
onClick={handleToggle}
70+
role="switch"
71+
aria-checked={isToggled}
72+
tabIndex={0}
73+
onKeyDown={(e) => {
74+
if (e.key === "Enter" || e.key === " ") handleToggle();
75+
}}
76+
>
77+
<div
78+
className={`flex h-6 w-6 transform items-center justify-center rounded-full shadow-lg transition-transform duration-400 ${
79+
isToggled
80+
? "bg-primary translate-x-[22px]"
81+
: "translate-x-0 bg-gray-600"
82+
}`}
83+
/>
84+
</div>
85+
</div>
86+
);
87+
};
88+
89+
export default Page;

src/components/icons/avatarIcon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export const AvatarIcon = (props: React.SVGProps<SVGSVGElement>) => (
77
{...props}
88
>
99
<path
10-
fill-rule="evenodd"
10+
fillRule="evenodd"
1111
d="M28.274 21.194c2.028 1.82 2.591 7.103 2.716 8.678a1.85 1.85 0 0 1-1.845 1.995h-13c-.05 0-.099-.01-.147-.015-.05.004-.098.015-.149.015H2.85a1.85 1.85 0 0 1-1.845-1.995c.125-1.575.688-6.858 2.716-8.677 1.305-1.17 2.207-1.589 3.416-1.95a1.85 1.85 0 0 1 1.061 3.545c-.703.21-1.112.357-2.006 1.16-.428.404-.94 2.194-1.259 4.218H15.85c.051 0 .1.01.15.014.047-.004.095-.014.146-.014h10.917c-.318-2.024-.83-3.815-1.26-4.22-.893-.8-1.3-.948-2.006-1.158a1.85 1.85 0 0 1 1.061-3.545c1.21.361 2.111.78 3.417 1.95ZM15.998 3.7c-2.343 0-4.322 2.855-4.322 6.235s1.979 6.235 4.322 6.235 4.322-2.856 4.322-6.235S18.34 3.7 15.998 3.7m0 16.17c-4.423 0-8.021-4.457-8.021-9.935S11.575 0 15.997 0c4.424 0 8.022 4.456 8.022 9.934s-3.598 9.934-8.021 9.934Z"
1212
/>
1313
</svg>

src/layouts/navigation/index.tsx

Lines changed: 156 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,96 @@
22
import { ReactNode } from "react";
33
import Link from "next/link";
44
import { usePathname } from "next/navigation";
5+
import {
6+
useFeatureFlagsStore,
7+
useHydratedFeatureFlags,
8+
} from "@/stores/featureFlags";
9+
10+
const NavigationSkeleton = () => {
11+
return (
12+
<div className="animate-pulse space-y-6 pt-1 md:ml-[-12px]">
13+
<ul>
14+
<li className="mb-1.5">
15+
<div className="flex items-start gap-4 rounded-md px-4 py-1">
16+
<div className="mt-1 h-5 w-5 rounded bg-gray-200"></div>
17+
<div className="h-5 w-20 rounded bg-gray-200"></div>
18+
</div>
19+
</li>
20+
</ul>
21+
22+
<ul>
23+
<li className="mb-1.5">
24+
<div className="flex items-start gap-4 rounded-md px-4 py-1">
25+
<div className="mt-1 h-5 w-5 rounded bg-gray-200"></div>
26+
<div className="h-5 w-32 rounded bg-gray-200"></div>
27+
</div>
28+
</li>
29+
<li className="mb-1.5">
30+
<div className="flex items-start gap-4 rounded-md px-4 py-1">
31+
<div className="mt-1 h-5 w-5 rounded bg-gray-200"></div>
32+
<div className="h-5 w-40 rounded bg-gray-200"></div>
33+
</div>
34+
</li>
35+
</ul>
36+
37+
<ul>
38+
<li className="mb-1.5">
39+
<div className="flex items-start gap-4 rounded-md px-4 py-1">
40+
<div className="mt-1 h-5 w-5 rounded bg-gray-200"></div>
41+
<div className="h-5 w-36 rounded bg-gray-200"></div>
42+
</div>
43+
</li>
44+
<li className="mb-1.5">
45+
<div className="flex items-start gap-4 rounded-md px-4 py-1">
46+
<div className="mt-1 h-5 w-5 rounded bg-gray-200"></div>
47+
<div className="h-5 w-36 rounded bg-gray-200"></div>
48+
</div>
49+
</li>
50+
<li className="mb-1.5">
51+
<div className="flex items-start gap-4 rounded-md px-4 py-1">
52+
<div className="mt-1 h-5 w-5 rounded bg-gray-200"></div>
53+
<div className="h-5 w-28 rounded bg-gray-200"></div>
54+
</div>
55+
</li>
56+
<li className="mb-1.5">
57+
<div className="flex items-start gap-4 rounded-md px-4 py-1">
58+
<div className="mt-1 h-5 w-5 rounded bg-gray-200"></div>
59+
<div className="h-5 w-32 rounded bg-gray-200"></div>
60+
</div>
61+
</li>
62+
<li className="mb-1.5">
63+
<div className="flex items-start gap-4 rounded-md px-4 py-1">
64+
<div className="mt-1 h-5 w-5 rounded bg-gray-200"></div>
65+
<div className="h-5 w-36 rounded bg-gray-200"></div>
66+
</div>
67+
</li>
68+
</ul>
69+
70+
<ul>
71+
<li className="mb-1.5">
72+
<div className="flex items-start gap-4 rounded-md px-4 py-1">
73+
<div className="mt-1 h-5 w-5 rounded bg-gray-200"></div>
74+
<div className="h-5 w-28 rounded bg-gray-200"></div>
75+
</div>
76+
</li>
77+
</ul>
78+
</div>
79+
);
80+
};
581

682
const Navigation = () => {
783
const pathname = usePathname();
84+
const isHydrated = useHydratedFeatureFlags();
85+
const currentFlags = useFeatureFlagsStore((s) => s.flags);
86+
87+
const hasAnyTrueFlag = Object.values(currentFlags).some(
88+
(flag) => flag === true,
89+
);
90+
91+
if (!isHydrated) return <NavigationSkeleton />;
92+
893
return (
9-
<div className="pt-1 md:ml-[-12px]">
94+
<div className="space-y-6 pt-1 md:ml-[-12px]">
1095
<ul>
1196
<SidebarMenuItem currentPage={pathname} text={"Home"} route={"/"}>
1297
<g fill="currentColor">
@@ -16,7 +101,7 @@ const Navigation = () => {
16101
</SidebarMenuItem>
17102
</ul>
18103

19-
<ul className="py-4">
104+
<ul>
20105
<SidebarMenuItem
21106
currentPage={pathname}
22107
text={"Berichtenbox"}
@@ -37,23 +122,9 @@ const Navigation = () => {
37122
>
38123
<path d="M3.24 10.44c.176.008.335.064.49.136 1.281.599 2.566 1.191 3.844 1.796.283.134.536.133.816.003 1.282-.597 2.571-1.181 3.851-1.78.392-.184.754-.208 1.138.013.268.152.562.267.84.404.206.1.21.182.015.294-.134.077-.28.136-.422.2-1.832.824-3.666 1.646-5.496 2.477-.282.128-.534.132-.816 0-1.904-.885-3.814-1.761-5.72-2.641-.09-.041-.203-.073-.202-.186.002-.105.114-.13.196-.165.376-.164.754-.325 1.13-.486.106-.046.218-.064.334-.065ZM3.246 7.44c.152-.007.298.045.441.112 1.283.596 2.572 1.184 3.848 1.794.323.154.599.145.912-.002 1.27-.594 2.546-1.174 3.816-1.766.368-.172.716-.191 1.082.006.279.15.576.273.862.411.226.11.235.202.006.314-.471.228-.95.44-1.429.656-1.472.662-2.946 1.32-4.414 1.992-.318.145-.597.149-.917 0-1.821-.85-3.648-1.687-5.474-2.528-.065-.029-.13-.058-.192-.09-.087-.045-.203-.074-.206-.184-.003-.118.12-.14.206-.178.358-.156.718-.306 1.074-.461.127-.055.233-.076.385-.076ZM7.91 7.584c.142.014.272-.046.4-.105l1.821-.819c1.31-.589 2.622-1.178 3.93-1.77.138-.062.326-.109.319-.288-.006-.162-.2-.174-.321-.229-1.451-.672-2.905-1.337-4.358-2.002-.45-.206-.904-.408-1.356-.61-.246-.112-.513-.11-.619-.003-1.981.909-3.963 1.814-5.944 2.722-.086.039-.208.064-.202.182.006.111.122.14.21.181l5.744 2.648c.117.053.234.103.376.093Z" />
39124
</SidebarMenuItem>
40-
<SidebarMenuItem
41-
currentPage={pathname}
42-
text={"Lopende zaken"}
43-
route={"/zaken"}
44-
>
45-
<path
46-
d="M17.22 0H4.03C3.56 0 3.26 0.31 3.26 0.78V4.65H0.78C0.57 4.66 0.38 0.74 0.23 4.88C0.08 5.11 0 5.26 0 5.49L0.78 11.16C1.16 14.09 2.71 14.72 4.03 14.72H13.33C15.86 14.72 17.99 12.59 17.99 10.07V0.78C17.99 0.31 17.69 0 17.22 0ZM16.45 10.07C16.45 10.89 16.13 11.67 15.56 12.24C14.99 12.81 14.21 13.13 13.33 13.16H3.72C4.27 12.52 4.81 11.52 4.81 10.07V1.55H16.45V10.07ZM6.36 3.87H14.88V5.42H6.36V3.87Z"
47-
fill="#282828"
48-
/>
49-
<path
50-
d="M6.36 6.98H10.23V7.75H6.36V6.98ZM6.36 8.53H10.23V9.3H6.36V8.53ZM6.36 10.07H10.23V10.85H6.36V10.07ZM11.01 10.85H13.57C14.26 10.85 14.88 10.23 14.88 9.53V6.98H11.01V10.85Z"
51-
fill="#282828"
52-
/>
53-
</SidebarMenuItem>
54125
</ul>
55126

56-
<ul className="py-4">
127+
<ul>
57128
<SidebarMenuItem
58129
currentPage={pathname}
59130
text={"Bedrijfsgegevens"}
@@ -112,6 +183,74 @@ const Navigation = () => {
112183
/>
113184
</SidebarMenuItem>
114185
</ul>
186+
187+
{hasAnyTrueFlag && (
188+
<ul>
189+
{currentFlags.feature_MijnZaken && (
190+
<SidebarMenuItem
191+
currentPage={pathname}
192+
text={"Mijn Zaken (Beta)"}
193+
route={"#"}
194+
>
195+
<path
196+
d="M3.246 7.44c.152-.007.298.045.441.112 1.283.596 2.572 1.184 3.848 1.794.323.154.599.145.912-.002 1.27-.594 2.546-1.174 3.816-1.766.368-.172.716-.191 1.082.006.279.15.576.273.862.411.226.11.235.202.006.314-.471.228-.95.44-1.429.656-1.472.662-2.946 1.32-4.414 1.992-.318.145-.597.149-.917 0-1.821-.85-3.648-1.687-5.474-2.528-.065-.029-.13-.058-.192-.09-.087-.045-.203-.074-.206-.184-.003-.118.12-.14.206-.178.358-.156.718-.306 1.074-.461.127-.055.233-.076.385-.076ZM7.91 7.584c.142.014.272-.046.4-.105l1.821-.819c1.31-.589 2.622-1.178 3.93-1.77.138-.062.326-.109.319-.288-.006-.162-.2-.174-.321-.229-1.451-.672-2.905-1.337-4.358-2.002-.45-.206-.904-.408-1.356-.61-.246-.112-.513-.11-.619-.003-1.981.909-3.963 1.814-5.944 2.722-.086.039-.208.064-.202.182.006.111.122.14.21.181l5.744 2.648c.117.053.234.103.376.093Z"
197+
fill="#282828"
198+
/>
199+
</SidebarMenuItem>
200+
)}
201+
{currentFlags.feature_MijnTaken && (
202+
<SidebarMenuItem
203+
currentPage={pathname}
204+
text={"Mijn Taken (Beta)"}
205+
route={"#"}
206+
>
207+
<path
208+
d="M3.246 7.44c.152-.007.298.045.441.112 1.283.596 2.572 1.184 3.848 1.794.323.154.599.145.912-.002 1.27-.594 2.546-1.174 3.816-1.766.368-.172.716-.191 1.082.006.279.15.576.273.862.411.226.11.235.202.006.314-.471.228-.95.44-1.429.656-1.472.662-2.946 1.32-4.414 1.992-.318.145-.597.149-.917 0-1.821-.85-3.648-1.687-5.474-2.528-.065-.029-.13-.058-.192-.09-.087-.045-.203-.074-.206-.184-.003-.118.12-.14.206-.178.358-.156.718-.306 1.074-.461.127-.055.233-.076.385-.076ZM7.91 7.584c.142.014.272-.046.4-.105l1.821-.819c1.31-.589 2.622-1.178 3.93-1.77.138-.062.326-.109.319-.288-.006-.162-.2-.174-.321-.229-1.451-.672-2.905-1.337-4.358-2.002-.45-.206-.904-.408-1.356-.61-.246-.112-.513-.11-.619-.003-1.981.909-3.963 1.814-5.944 2.722-.086.039-.208.064-.202.182.006.111.122.14.21.181l5.744 2.648c.117.053.234.103.376.093Z"
209+
fill="#282828"
210+
/>
211+
</SidebarMenuItem>
212+
)}
213+
{currentFlags.feature_MijnProducten && (
214+
<SidebarMenuItem
215+
currentPage={pathname}
216+
text={"Mijn Producten (Beta)"}
217+
route={"#"}
218+
>
219+
<path
220+
d="M3.246 7.44c.152-.007.298.045.441.112 1.283.596 2.572 1.184 3.848 1.794.323.154.599.145.912-.002 1.27-.594 2.546-1.174 3.816-1.766.368-.172.716-.191 1.082.006.279.15.576.273.862.411.226.11.235.202.006.314-.471.228-.95.44-1.429.656-1.472.662-2.946 1.32-4.414 1.992-.318.145-.597.149-.917 0-1.821-.85-3.648-1.687-5.474-2.528-.065-.029-.13-.058-.192-.09-.087-.045-.203-.074-.206-.184-.003-.118.12-.14.206-.178.358-.156.718-.306 1.074-.461.127-.055.233-.076.385-.076ZM7.91 7.584c.142.014.272-.046.4-.105l1.821-.819c1.31-.589 2.622-1.178 3.93-1.77.138-.062.326-.109.319-.288-.006-.162-.2-.174-.321-.229-1.451-.672-2.905-1.337-4.358-2.002-.45-.206-.904-.408-1.356-.61-.246-.112-.513-.11-.619-.003-1.981.909-3.963 1.814-5.944 2.722-.086.039-.208.064-.202.182.006.111.122.14.21.181l5.744 2.648c.117.053.234.103.376.093Z"
221+
fill="#282828"
222+
/>
223+
</SidebarMenuItem>
224+
)}
225+
{currentFlags.feature_RegelRecht && (
226+
<SidebarMenuItem
227+
currentPage={pathname}
228+
text={"RegelRecht (Beta)"}
229+
route={"#"}
230+
>
231+
<path
232+
d="M3.246 7.44c.152-.007.298.045.441.112 1.283.596 2.572 1.184 3.848 1.794.323.154.599.145.912-.002 1.27-.594 2.546-1.174 3.816-1.766.368-.172.716-.191 1.082.006.279.15.576.273.862.411.226.11.235.202.006.314-.471.228-.95.44-1.429.656-1.472.662-2.946 1.32-4.414 1.992-.318.145-.597.149-.917 0-1.821-.85-3.648-1.687-5.474-2.528-.065-.029-.13-.058-.192-.09-.087-.045-.203-.074-.206-.184-.003-.118.12-.14.206-.178.358-.156.718-.306 1.074-.461.127-.055.233-.076.385-.076ZM7.91 7.584c.142.014.272-.046.4-.105l1.821-.819c1.31-.589 2.622-1.178 3.93-1.77.138-.062.326-.109.319-.288-.006-.162-.2-.174-.321-.229-1.451-.672-2.905-1.337-4.358-2.002-.45-.206-.904-.408-1.356-.61-.246-.112-.513-.11-.619-.003-1.981.909-3.963 1.814-5.944 2.722-.086.039-.208.064-.202.182.006.111.122.14.21.181l5.744 2.648c.117.053.234.103.376.093Z"
233+
fill="#282828"
234+
/>
235+
</SidebarMenuItem>
236+
)}
237+
</ul>
238+
)}
239+
240+
<ul>
241+
<SidebarMenuItem
242+
currentPage={pathname}
243+
text={"Instellingen"}
244+
route={"/instellingen"}
245+
>
246+
<g fill="currentColor" fillRule="evenodd">
247+
<path
248+
fill="currentColor"
249+
d="M10 7.438A2.568 2.568 0 0 0 7.434 10 2.57 2.57 0 0 0 10 12.564 2.567 2.567 0 0 0 12.565 10 2.565 2.565 0 0 0 10 7.438zm8 2.978a.71.71 0 0 1-.382.596l-1.427.66a1.13 1.13 0 0 0-.548.545l-.08.195c-.089.216-.081.565.017.776l.564 1.431a.688.688 0 0 1-.137.69l-.648.648a.706.706 0 0 1-.688.148l-1.471-.543a1.142 1.142 0 0 0-.77-.007l-.207.086a1.093 1.093 0 0 0-.53.558l-.615 1.411a.685.685 0 0 1-.58.39h-.923a.704.704 0 0 1-.589-.386l-.656-1.412a1.142 1.142 0 0 0-.541-.554l-.208-.086a1.094 1.094 0 0 0-.764.017l-1.441.569a.685.685 0 0 1-.684-.139l-.65-.649a.712.712 0 0 1-.146-.693l.538-1.463c.093-.214.096-.565.007-.78l-.08-.193a1.09 1.09 0 0 0-.554-.535l-1.422-.619A.687.687 0 0 1 2 10.49v-.907a.71.71 0 0 1 .38-.596l1.425-.657c.215-.083.461-.329.55-.544l.08-.196c.09-.216.081-.565-.016-.776l-.563-1.431a.688.688 0 0 1 .136-.689l.648-.648a.705.705 0 0 1 .689-.149l1.475.541c.21.092.557.095.77.006l.203-.084c.21-.088.45-.339.53-.558l.615-1.411A.686.686 0 0 1 9.502 2h.923c.228 0 .494.174.589.386l.655 1.414c.085.217.329.466.541.554l.208.085c.211.088.555.08.763-.017l1.443-.568a.685.685 0 0 1 .684.139l.648.647a.71.71 0 0 1 .146.693l-.536 1.463a1.15 1.15 0 0 0-.007.781l.08.197c.09.215.337.455.554.533l1.421.618a.687.687 0 0 1 .386.586v.905z"
250+
></path>
251+
</g>
252+
</SidebarMenuItem>
253+
</ul>
115254
</div>
116255
);
117256
};

0 commit comments

Comments
 (0)