Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STUD-375: Reactor client config flags with launch darkly feature flags #798

Merged
merged 2 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion apps/marketplace/src/modules/content/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// eslint-disable-next-line
/**
* @deprecated Use Launch Darkly feature flags instead.
*/
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface FeatureFlags {
// When a feature flag is added it will have the following format:
// readonly exampleFlag: boolean;
Expand Down
3 changes: 3 additions & 0 deletions apps/studio/src/modules/content/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export interface Country {
readonly state?: State[];
}

/**
* @deprecated Use Launch Darkly feature flags instead.
*/
interface FeatureFlags {
readonly claimWalletRoyaltiesEnabled: boolean;
readonly manageMarketplaceSalesEnabled: boolean;
Expand Down
12 changes: 3 additions & 9 deletions apps/studio/src/pages/home/library/ViewDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Button, ProfileImage, Tooltip } from "@newm-web/elements";
import theme from "@newm-web/theme";
import { resizeCloudinaryImage } from "@newm-web/utils";
import { MintingStatus } from "@newm-web/types";
import { useFlags } from "launchdarkly-react-client-sdk";
import MintSong from "./MintSong";
import SongInfo from "./SongInfo";
import { SongRouteParams } from "./types";
Expand All @@ -19,7 +20,6 @@ import {
useGetSongQuery,
useHasSongAccess,
} from "../../../modules/song";
import { useGetStudioClientConfigQuery } from "../../../modules/content";

interface TabPanelProps {
children: ReactNode;
Expand Down Expand Up @@ -70,22 +70,16 @@ const ViewDetails: FunctionComponent = () => {
isLoading,
} = useGetSongQuery(songId);

const { data: clientConfig, isLoading: isClientConfigLoading } =
useGetStudioClientConfigQuery();
const { webStudioManageMarketplaceSales } = useFlags();

const hasAccess = useHasSongAccess(songId);
const isSongMintedOrReleased = [
MintingStatus.Minted,
MintingStatus.Released,
].includes(mintingStatus);

const isManageMarketplaceSalesEnabled =
clientConfig?.featureFlags?.manageMarketplaceSalesEnabled ?? false;

const shouldRenderMarketplaceTab =
!isClientConfigLoading &&
isSongMintedOrReleased &&
isManageMarketplaceSalesEnabled;
isSongMintedOrReleased && webStudioManageMarketplaceSales;

const handleChange = (event: SyntheticEvent, nextTab: number) => {
setTab(nextTab);
Expand Down
12 changes: 3 additions & 9 deletions apps/studio/src/pages/home/wallet/Wallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ import {
convertNewmiesToUsd,
} from "@newm-web/utils";
import { EarningsInProgress } from "@newm-web/types";
import { useFlags } from "launchdarkly-react-client-sdk";
import Portfolio from "./portfolio/Portfolio";
import Transactions from "./transactions/Transactions";
import { LegacyPortfolio, LegacyUnclaimedRoyalties } from "./legacyWallet";
import {
useGetAdaUsdConversionRateQuery,
useGetNewmUsdConversionRateQuery,
} from "../../../modules/crypto";
import { useGetStudioClientConfigQuery } from "../../../modules/content";
import { setIsConnectWalletModalOpen } from "../../../modules/ui";
import { useAppDispatch, useAppSelector } from "../../../common";
import { DisconnectWalletButton } from "../../../components";
Expand Down Expand Up @@ -89,8 +89,7 @@ const Wallet: FunctionComponent = () => {
const [earningsInProgress, setEarningsInProgress] =
useState<EarningsInProgress>();
const { wallet } = useConnectWallet();
const { data: clientConfig, isLoading: isClientConfigLoading } =
useGetStudioClientConfigQuery();
const { webStudioClaimWalletEarnings } = useFlags();
const { walletAddress = "" } = useAppSelector(selectWallet);
const {
data: earningsData,
Expand All @@ -112,8 +111,6 @@ const Wallet: FunctionComponent = () => {
const preConvertedUsdPrice = newmUsdConversionRate?.usdPrice ?? 0;
const { earnings = [], amountCborHex = "" } = earningsData || {};

const isClaimWalletRoyaltiesEnabled =
clientConfig?.featureFlags?.claimWalletRoyaltiesEnabled ?? false;
const unclaimedEarnings =
earnings?.filter((earning) => !earning.claimed) || [];
const unclaimedEarningsInNewmies =
Expand Down Expand Up @@ -189,11 +186,8 @@ const Wallet: FunctionComponent = () => {
};
}, [handleSaleEndPending]);

// Don't show any content until client config has loaded
if (isClientConfigLoading) return;

// Current State of the Wallet Page
if (!isClaimWalletRoyaltiesEnabled) {
if (!webStudioClaimWalletEarnings) {
return (
<Container maxWidth={ false }>
<Box ml={ [null, null, 3] }>
Expand Down
46 changes: 37 additions & 9 deletions docs/launch-darkly-feature-flags.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
# Feature Flag Naming Conventions for LaunchDarkly
# Feature Flag Naming Conventions and Usage for LaunchDarkly

We use LaunchDarkly (LD) as our feature flag solution to manage and control feature releases across different applications in our NX monorepo. To maintain consistency and clarity, all feature flags should adhere to a standard naming convention.

## Naming Format

```
platform + appName + flagName
platform + app-name + flag-name
```

### Naming Rules

- **Format**: Use camelCase.
- **Format**: Use kebab-case.
- **Platform**: For our use case the most common one we will use is `web`, but it applies for other NEWM platforms like `server` or `mobile`.
- **App Names**: At the time of writing our current apps are `studio`, `marketplace`, `wallet`, and `tools`.
- **Flag Name**: Clearly describe the feature being controlled, using camelCase.
- **Flag Name**: Clearly describe the feature being controlled, using kebab-case.

## Examples for LaunchDarkly Feature Flags

- `webStudioMaintenanceMode`
- `webMarketplaceRoyaltyClaiming`
- `webWalletMultipleConnections`
- `webToolsInternationalCurrency`
- `web-studio-maintenance-mode`
- `web-marketplace-royalty-claiming`
- `web-wallet-multiple-connections`
- `web-tools-international-currency`

## Why Use This Convention?

Expand All @@ -35,6 +35,34 @@ platform + appName + flagName
- **Keep the flag name concise but meaningful**, avoiding ambiguity.
- **Avoid using the word `new`** as this is relative.
- **Avoid prefixes like `is` or `has`** unless necessary: Although common in coding, they can add unnecessary length to flag names.
- **Use camelCase** for readability and adherence to standard naming conventions.
- **Use kebab-case** for readability and adherence to standard naming conventions.

By following these guidelines, we can ensure effective and scalable feature flag management across our monorepo and different NEWM platforms with LaunchDarkly.

## Usage

To access a feature flag in your React app using the `useFlags` hook:

**LD Flag Name**: `web-marketplace-launch-banner`

```javascript
import { useFlags } from "launchdarkly-react-client-sdk";

const MyComponent = () => {
const { webMarketplaceLaunchBanner } = useFlags();

return (
<div>
{webMarketplaceLaunchBanner ? (
<p>The launch banner feature is enabled!</p>
) : (
<p>The launch banner feature is disabled.</p>
)}
</div>
);
};

export default MyComponent;
```

Note that even though the flag name in LD is `kebab-case`, we are able to access it `camelCase` in our app.
Loading