Skip to content

Commit

Permalink
feat: add new header flag, minor fixes (#12)
Browse files Browse the repository at this point in the history
Signed-off-by: Todd Baert <[email protected]>
  • Loading branch information
toddbaert authored Nov 13, 2024
1 parent 0ae944f commit f9dd4f8
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 24 deletions.
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ Open [http://localhost:3000](http://localhost:3000) with your browser to see the

ToggleShop leverages a number of feature flags for various technical and business-related use cases.

| Feature Flag | Type | Default Variant | Variants |
| ------------------- | ------- | --------------- | ----------- |
| offer-free-shipping | boolean | true | true, false |
| use-distributed-db | boolean | false | true, false |
| use-secure-protocol | boolean | false | true, false |

> The flag configuration can be found [here](./flags.json).
| Feature Flag | Type | Default Variant | Variants |
| ------------------- | ------- | --------------- | -------- |
| offer-free-shipping | boolean | on | on, off |
| sticky-header | boolean | off | on, off |
| use-distributed-db | boolean | off | on, off |
| use-secure-protocol | boolean | off | on, off |

> The flag configuration for local development can be found [here](./flags.json).
### Free Shipping

Expand Down
33 changes: 22 additions & 11 deletions flags.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,43 @@
"offer-free-shipping": {
"state": "ENABLED",
"variants": {
"true": true,
"false": false
"on": true,
"off": false
},
"defaultVariant": "true"
"defaultVariant": "on"
},
"sticky-header": {
"state": "ENABLED",
"variants": {
"on": true,
"off": false
},
"defaultVariant": "on",
"targeting": {
"if": [{ "==": [{ "var": "size" }, "sm"]}, "on", "off" ]
}
},
"use-distributed-db": {
"state": "ENABLED",
"variants": {
"true": true,
"false": false
"on": true,
"off": false
},
"targeting": {
"fractional": [
["true", 0],
["false", 100]
["on", 0],
["off", 100]
]
},
"defaultVariant": "false"
"defaultVariant": "off"
},
"use-secure-protocol": {
"state": "ENABLED",
"variants": {
"true": true,
"false": false
"on": true,
"off": false
},
"defaultVariant": "false"
"defaultVariant": "off"
}
}
}
13 changes: 13 additions & 0 deletions kubernetes/toggle-shop.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ spec:
'on': true
'off': false
defaultVariant: 'on'
sticky-header:
state: ENABLED
variants:
'on': true
'off': false
defaultVariant: 'off'
# targeting:
# if:
# - "==":
# - var: size
# - sm
# - 'on'
# - 'off'
---
# Flags for our backend application
apiVersion: core.openfeature.dev/v1beta1
Expand Down
2 changes: 1 addition & 1 deletion src/app/api/ofrep/v1/evaluate/flags/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ if (process.env.FLAGD_OFFLINE_FLAG_SOURCE_PATH) {
}

export async function POST(request: Request) {
const context = await request.json();
const { context } = await request.json();

// We have to map these names to be compatible with OFREP
const flags = flagdCore
Expand Down
7 changes: 5 additions & 2 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@

import Link from "next/link";
import { ShoppingCart, Menu, X } from "lucide-react";
import { useState } from "react";
import { CSSProperties, useState } from "react";
import { useCart } from "@/hooks/use-cart";
import { useFlag } from "@openfeature/react-sdk";

export default function Header() {
const [isMenuOpen, setIsMenuOpen] = useState(false);
const { cartItems } = useCart();
const { value: stickyHeader } = useFlag('sticky-header', false);
const headerStyle: CSSProperties = stickyHeader ? { position: 'sticky', top: 0, zIndex: 1000 } : {};
const cartItemsCount = cartItems.reduce(
(total, item) => total + item.quantity,
0
);

return (
<header className="bg-white shadow-md">
<header style={headerStyle} className="bg-white shadow-md">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center py-4 md:justify-start md:space-x-10">
<div className="flex justify-start lg:w-0 lg:flex-1">
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/use-products.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { getBaseUrl } from "@/libs/url";
import { tanstackMetaToHeader } from "@/libs/open-feature/evaluation-context";

export function useProducts() {
console.log("fetching products");
const { data } = useSuspenseQuery({
queryKey: ["products"],
queryFn: async ({ meta }): Promise<Product[]> => {
console.log("fetching products");
const res = await fetch(getBaseUrl() + "/api/products", {
cache: "no-store",
headers: tanstackMetaToHeader(meta),
Expand All @@ -24,10 +24,10 @@ export function useProducts() {
}

export function useProduct(id: string) {
console.log(`fetching product ${id}`);
const { data } = useSuspenseQuery({
queryKey: ["products", id],
queryFn: async ({ meta }): Promise<Product> => {
console.log(`fetching product ${id}`);
const res = await fetch(getBaseUrl() + `/api/products/${id}`, {
cache: "no-store",
headers: tanstackMetaToHeader(meta),
Expand Down
28 changes: 28 additions & 0 deletions src/hooks/use-size.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"use client";

import { useEffect, useState } from "react";

type Size = "sm" | "md" | "lg" | "xl";

const computeSize = (): Size => {
return globalThis.innerWidth < 768 ? 'sm' : globalThis.innerWidth < 992 ? 'md' : globalThis.innerWidth < 1200 ? 'lg' : 'xl';
}

export function useSize() {

const [size, setSize] = useState(computeSize());
const resizeListener = () => {
const newSize = computeSize();
setSize(newSize);
};

useEffect(() => {
globalThis.addEventListener('resize', resizeListener);
return () => {
globalThis.removeEventListener('resize', resizeListener)
};
}, []);

return size;

}
10 changes: 9 additions & 1 deletion src/providers/open-feature.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useEffect, useRef } from "react";
import { ClientEventHook } from "@/libs/open-feature/client-event-hook";
import { getBaseUrl } from "@/libs/url";
import { ATTR_FEATURE_FLAG_CONTEXT_ID } from "@/libs/open-feature/proposed-attributes";
import { useSize } from "@/hooks/use-size";

class OFREPWebEventProvider extends OFREPWebProvider implements Provider {
metadata = { name: "OREFP" };
Expand Down Expand Up @@ -47,6 +48,13 @@ export function OpenFeatureProvider({
children: React.ReactNode;
}) {
const hasInitialized = useRef(false);
const size = useSize();

useEffect(() => {
if (hasInitialized.current) {
OpenFeature.setContext({ ...OpenFeature.getContext(), size });
}
}, [size])

useEffect(() => {
if (!hasInitialized.current) {
Expand All @@ -59,7 +67,7 @@ export function OpenFeatureProvider({
// A real app may want to only update on page load.
pollInterval: 5000,
}),
context
{...context, size}
);
hasInitialized.current = true;
}
Expand Down

0 comments on commit f9dd4f8

Please sign in to comment.