Skip to content

Conversation

tiagoapolo
Copy link

@tiagoapolo tiagoapolo commented Jun 10, 2025

final work

Description

This PR adds an usage example for Flagsmith Adapter implement in vercel/flags#103

Demo URL

https://flagsmith-six.vercel.app/

Type of Change

  • New Example
  • Example updates (Bug fixes, new features, etc.)
  • Other (changes to the codebase, but not to examples)

New Example Checklist

  • 🛫 npm run new-example was used to create the example
  • 📚 The template wasn't used but I carefuly read the Adding a new example steps and implemented them in the example
  • 📱 Is it responsive? Are mobile and tablets considered?

Copy link

vercel bot commented Jun 10, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
app-dir-css-in-js Ready Ready Preview Comment Aug 19, 2025 2:22pm
app-dir-i18n Ready Ready Preview Comment Aug 19, 2025 2:22pm
app-dir-share-state Ready Ready Preview Comment Aug 19, 2025 2:22pm
edge-api-routes-cache-control Error Error Aug 19, 2025 2:22pm
edge-api-routes-hello-world Error Error Aug 19, 2025 2:22pm
edge-api-routes-json-response Error Error Aug 19, 2025 2:22pm
edge-api-routes-query-parameters Error Error Aug 19, 2025 2:22pm
edge-functions-authed-proxy Error Error Aug 19, 2025 2:22pm
edge-functions-cookies Ready Ready Preview Comment Aug 19, 2025 2:22pm
edge-functions-news Error Error Aug 19, 2025 2:22pm
edge-functions-streams Error Error Aug 19, 2025 2:22pm
edge-geolocation-country-block Ready Ready Preview Comment Aug 19, 2025 2:22pm
edge-middleware-modify-request-header Ready Ready Preview Comment Aug 19, 2025 2:22pm
edge-user-agent-based-rendering Ready Ready Preview Comment Aug 19, 2025 2:22pm
example-auth-with-ory Error Error Aug 19, 2025 2:22pm
example-reduce-image-bandwidth-usage Ready Ready Preview Comment Aug 19, 2025 2:22pm
geolocation-script Ready Ready Preview Comment Aug 19, 2025 2:22pm
i18n Ready Ready Preview Comment Aug 19, 2025 2:22pm
next-edge-api-route-hello-world Error Error Aug 19, 2025 2:22pm
next-flask Ready Ready Preview Comment Aug 19, 2025 2:22pm
nodejs-api Ready Ready Preview Comment Aug 19, 2025 2:22pm
redirect-with-fallback Ready Ready Preview Comment Aug 19, 2025 2:22pm
redirects-bloom-filter Ready Ready Preview Comment Aug 19, 2025 2:22pm
solutions-combining-data-fetching-strategies Ready Ready Preview Comment Aug 19, 2025 2:22pm
solutions-image-fallback Ready Ready Preview Comment Aug 19, 2025 2:22pm
solutions-image-offset Ready Ready Preview Comment Aug 19, 2025 2:22pm
solutions-loading-web-fonts Ready Ready Preview Comment Aug 19, 2025 2:22pm
solutions-microfrontends Ready Ready Preview Comment Aug 19, 2025 2:22pm
solutions-microfrontends-docs Ready Ready Preview Comment Aug 19, 2025 2:22pm
solutions-pagination-with-ssg Ready Ready Preview Comment Aug 19, 2025 2:22pm
solutions-parallel-routes-navbar Error Error Aug 19, 2025 2:22pm
solutions-reuse-responses Ready Ready Preview Comment Aug 19, 2025 2:22pm
solutions-script-component-ad Ready Ready Preview Comment Aug 19, 2025 2:22pm
solutions-script-component-strategies Ready Ready Preview Comment Aug 19, 2025 2:22pm
solutions-testing Ready Ready Preview Comment Aug 19, 2025 2:22pm
wasm-rust-hello-world Building Building Preview Comment Aug 19, 2025 2:22pm
wasm-rust-xor Building Building Preview Comment Aug 19, 2025 2:22pm

Copy link

vercel bot commented Jun 10, 2025

@tiagoapolo is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

return (
<button
type="button"
className={`${colorMap[color]} cursor-pointer w-full rounded-full border border-transparent px-4 py-3 text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-50`}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
className={`${colorMap[color]} cursor-pointer w-full rounded-full border border-transparent px-4 py-3 text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-50`}
className={`${colorMap[color] || colorMap.blue} cursor-pointer w-full rounded-full border border-transparent px-4 py-3 text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-50`}

The ProceedToCheckoutButton uses colorMap[color] without handling cases where color is not in the map, which could result in undefined CSS classes and broken styling.

View Details

Analysis

The ProceedToCheckoutButton component accesses colorMap[color] directly without checking if the color exists in the map. The proceedToCheckoutColorFlag can have a default value of 'blue' and options of ['blue', 'green', 'red'], but if an invalid color value is somehow passed or if the flag system returns an unexpected value, colorMap[color] will be undefined.

When undefined is interpolated into the className string, it becomes the literal text "undefined" in the CSS class, which is not a valid Tailwind class and will result in no styling being applied to the button.


Recommendation

Add a fallback for missing colors in the color map:

className={`${colorMap[color] || colorMap.blue} cursor-pointer w-full rounded-full border border-transparent px-4 py-3 text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-50`}

Or add a default case to the colorMap and use nullish coalescing:

const colorMap: Record<string, string> = {
  blue: 'bg-blue-600 hover:bg-blue-700',
  red: 'bg-red-600 hover:bg-red-700', 
  green: 'bg-green-600 hover:bg-green-700',
  default: 'bg-blue-600 hover:bg-blue-700',
}

// Then use: colorMap[color] || colorMap.default

Comment on lines +21 to +23
return fetch(`${BACKEND_URL}/api/cart/${cartId.value}`).then((res) =>
res.json()
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getCart function doesn't handle network errors or non-successful HTTP responses, which could cause the shopping cart to fail silently or throw unhandled exceptions.

View Details
📝 Patch Details
diff --git a/flags-sdk/flagsmith/lib/actions.ts b/flags-sdk/flagsmith/lib/actions.ts
index deb694df..4821d513 100644
--- a/flags-sdk/flagsmith/lib/actions.ts
+++ b/flags-sdk/flagsmith/lib/actions.ts
@@ -18,9 +18,13 @@ export async function getCart(): Promise<Cart> {
   const cartId = await getCartId()
   const delayMs = await delayFlag()
   await delay(delayMs)
-  return fetch(`${BACKEND_URL}/api/cart/${cartId.value}`).then((res) =>
-    res.json()
-  )
+  
+  const response = await fetch(`${BACKEND_URL}/api/cart/${cartId.value}`)
+  if (!response.ok) {
+    throw new Error(`Failed to fetch cart: ${response.status}`)
+  }
+  
+  return response.json()
 }
 
 export async function addToCart(item: CartItem) {

Analysis

The getCart function makes a fetch request and directly calls res.json() without checking if the response was successful (status 200-299). If the API returns an error status code (404, 500, etc.) or if there's a network failure, this will either throw an unhandled exception or return malformed data.

The same issue exists in addToCart and removeFromCart functions, but they're fire-and-forget operations where the lack of error handling is less critical. However, getCart is used to render the shopping cart UI, so failures here directly impact the user interface.


Recommendation

Add response status checking and error handling:

export async function getCart(): Promise<Cart> {
  const cartId = await getCartId()
  const delayMs = await delayFlag()
  await delay(delayMs)
  
  const response = await fetch(`${BACKEND_URL}/api/cart/${cartId.value}`)
  if (!response.ok) {
    throw new Error(`Failed to fetch cart: ${response.status}`)
  }
  
  return response.json()
}

Comment on lines +22 to +27
onClick={async () => {
setIsLoading(true)
track('add_to_cart:clicked')
await addToCart({ id: 'shirt', color, size, quantity: 1 })
router.push('/cart')
}}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AddToCart component sets loading state to true but never resets it to false if the addToCart API call fails, leaving the button permanently in a loading state.

View Details
📝 Patch Details
diff --git a/flags-sdk/flagsmith/app/[code]/add-to-cart.tsx b/flags-sdk/flagsmith/app/[code]/add-to-cart.tsx
index c4d7c18b..f71625a7 100644
--- a/flags-sdk/flagsmith/app/[code]/add-to-cart.tsx
+++ b/flags-sdk/flagsmith/app/[code]/add-to-cart.tsx
@@ -21,9 +21,16 @@ export function AddToCart() {
       isLoading={isLoading}
       onClick={async () => {
         setIsLoading(true)
-        track('add_to_cart:clicked')
-        await addToCart({ id: 'shirt', color, size, quantity: 1 })
-        router.push('/cart')
+        try {
+          track('add_to_cart:clicked')
+          await addToCart({ id: 'shirt', color, size, quantity: 1 })
+          router.push('/cart')
+        } catch (error) {
+          console.error('Failed to add item to cart:', error)
+          // Optionally show error feedback to user
+        } finally {
+          setIsLoading(false)
+        }
       }}
     />
   )

Analysis

In the AddToCart component, the onClick handler sets isLoading to true at the start but has no error handling to reset it if the addToCart API call fails. If addToCart throws an error (network failure, server error, etc.), the component will remain in the loading state indefinitely, making the button unusable.

This creates a poor user experience where users can't retry the action after a network failure, and the UI provides no feedback about what went wrong.


Recommendation

Wrap the API call in a try-catch block and ensure setIsLoading(false) is called in the catch block:

onClick={async () => {
  setIsLoading(true)
  try {
    track('add_to_cart:clicked')
    await addToCart({ id: 'shirt', color, size, quantity: 1 })
    router.push('/cart')
  } catch (error) {
    console.error('Failed to add item to cart:', error)
    // Optionally show error feedback to user
  } finally {
    setIsLoading(false)
  }
}}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants