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

feat: add thirdweb fallback #2808

Merged
merged 5 commits into from
May 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 2 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"@fingerprintjs/fingerprintjs": "^3.4.1",
"@giphy/js-fetch-api": "4.9.0",
"@giphy/react-components": "6.9.0",
"@growthbook/growthbook-react": "^0.16.0",
"@growthbook/growthbook": "^0.26.0",
"@headlessui/react": "^1.7.14",
"@heroicons/react": "v1",
"@hookform/resolvers": "^3.1.0",
Expand All @@ -39,6 +39,7 @@
"@livepeer/react": "^2.4.3",
"@snapshot-labs/snapshot.js": "^0.4.82",
"@tanstack/react-query": "^4.29.5",
"@thirdweb-dev/storage": "^1.1.2",
"@tippyjs/react": "^4.2.6",
"@xmtp/xmtp-js": "8.2.0",
"abis": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
import { GrowthBook, GrowthBookProvider } from '@growthbook/growthbook-react';
import { GROWTHBOOK_KEY, IS_MAINNET, mainnetStaffs, testnetStaffs } from 'data';
import { Growthbook } from '@lib/growthbook';
import { IS_MAINNET, mainnetStaffs, testnetStaffs } from 'data';
import isGardener from 'lib/isGardener';
import type { FC, ReactNode } from 'react';
import type { FC } from 'react';
import { useEffect } from 'react';
import { useAppStore } from 'src/store/app';

const growthbook = new GrowthBook({
clientKey: GROWTHBOOK_KEY,
enableDevMode: false
});
Growthbook.init();

interface FeatureFlagsProviderProps {
children: ReactNode;
}

const FeatureFlagsProvider: FC<FeatureFlagsProviderProps> = ({ children }) => {
const FeatureFlagsProvider: FC = () => {
const currentProfile = useAppStore((state) => state.currentProfile);

useEffect(() => {
if (currentProfile?.id) {
growthbook.loadFeatures();
growthbook.setAttributes({
Growthbook.setAttributes({
id: `${IS_MAINNET ? 'mainnet' : 'testnet'}-${currentProfile.id}`,
isGardener: IS_MAINNET ? isGardener(currentProfile.id) : false,
isStaff: IS_MAINNET
Expand All @@ -32,9 +24,7 @@ const FeatureFlagsProvider: FC<FeatureFlagsProviderProps> = ({ children }) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentProfile]);

return (
<GrowthBookProvider growthbook={growthbook}>{children}</GrowthBookProvider>
);
return null;
};

export default FeatureFlagsProvider;
30 changes: 13 additions & 17 deletions apps/web/src/components/Common/Providers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,23 +64,19 @@ const Providers = ({ children }: { children: ReactNode }) => {
return (
<I18nProvider i18n={i18n}>
<ErrorBoundary>
<FeatureFlagsProvider>
<TelemetryProvider />
<WagmiConfig client={wagmiClient}>
<ApolloProvider client={apolloClient}>
<QueryClientProvider client={queryClient}>
<LivepeerConfig
client={livepeerClient}
theme={getLivepeerTheme}
>
<ThemeProvider defaultTheme="light" attribute="class">
<Layout>{children}</Layout>
</ThemeProvider>
</LivepeerConfig>
</QueryClientProvider>
</ApolloProvider>
</WagmiConfig>
</FeatureFlagsProvider>
<FeatureFlagsProvider />
<TelemetryProvider />
<WagmiConfig client={wagmiClient}>
<ApolloProvider client={apolloClient}>
<QueryClientProvider client={queryClient}>
<LivepeerConfig client={livepeerClient} theme={getLivepeerTheme}>
<ThemeProvider defaultTheme="light" attribute="class">
<Layout>{children}</Layout>
</ThemeProvider>
</LivepeerConfig>
</QueryClientProvider>
</ApolloProvider>
</WagmiConfig>
</ErrorBoundary>
</I18nProvider>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useFeature } from '@growthbook/growthbook-react';
import { MenuAlt2Icon } from '@heroicons/react/solid';
import { Growthbook } from '@lib/growthbook';
import { t } from '@lingui/macro';
import { FeatureFlag } from 'data';
import { motion } from 'framer-motion';
Expand All @@ -13,7 +13,7 @@ const PollSettings: FC = () => {
(state) => state.setShowPollEditor
);
const resetPollConfig = usePublicationStore((state) => state.resetPollConfig);
const { on: isPollsEnabled } = useFeature(FeatureFlag.Polls as string);
const { on: isPollsEnabled } = Growthbook.feature(FeatureFlag.Polls);

if (!isPollsEnabled) {
return null;
Expand Down
6 changes: 3 additions & 3 deletions apps/web/src/components/Explore/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import MetaTags from '@components/Common/MetaTags';
import RecommendedProfiles from '@components/Home/RecommendedProfiles';
import Trending from '@components/Home/Trending';
import Footer from '@components/Shared/Footer';
import { useFeature } from '@growthbook/growthbook-react';
import { Tab } from '@headlessui/react';
import { Growthbook } from '@lib/growthbook';
import { Mixpanel } from '@lib/mixpanel';
import { t } from '@lingui/macro';
import clsx from 'clsx';
Expand All @@ -25,8 +25,8 @@ const Explore: NextPage = () => {
const router = useRouter();
const currentProfile = useAppStore((state) => state.currentProfile);
const [focus, setFocus] = useState<PublicationMainFocus>();
const { on: isTrendingWidgetEnabled } = useFeature(
FeatureFlag.TrendingWidget as string
const { on: isTrendingWidgetEnabled } = Growthbook.feature(
FeatureFlag.TrendingWidget
);

useEffect(() => {
Expand Down
6 changes: 2 additions & 4 deletions apps/web/src/components/Profile/NftGallery/Detail/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import MetaTags from '@components/Common/MetaTags';
import Slug from '@components/Shared/Slug';
import UserProfile from '@components/Shared/UserProfile';
import { useFeature } from '@growthbook/growthbook-react';
import { Growthbook } from '@lib/growthbook';
import { Mixpanel } from '@lib/mixpanel';
import { FeatureFlag } from 'data/feature-flags';
import type { Profile } from 'lens';
Expand All @@ -18,9 +18,7 @@ import { Card, GridItemEight, GridItemFour, GridLayout, Image } from 'ui';
const NFTDetail: FC = () => {
const currentProfile = useAppStore((state) => state.currentProfile);
const profiles = useAppStore((state) => state.profiles);
const { on: isNftDetailEnabled } = useFeature(
FeatureFlag.NftDetail as string
);
const { on: isNftDetailEnabled } = Growthbook.feature(FeatureFlag.NftDetail);

useEffect(() => {
Mixpanel.track(PAGEVIEW, { page: 'nft' });
Expand Down
6 changes: 3 additions & 3 deletions apps/web/src/components/Profile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import MetaTags from '@components/Common/MetaTags';
import NftFeed from '@components/Nft/NftFeed';
import { useFeature } from '@growthbook/growthbook-react';
import { Growthbook } from '@lib/growthbook';
import { Mixpanel } from '@lib/mixpanel';
import { FeatureFlag } from 'data';
import { APP_NAME, STATIC_IMAGES_URL } from 'data/constants';
Expand Down Expand Up @@ -36,8 +36,8 @@ const ViewProfile: NextPage = () => {
? type.toString().toUpperCase()
: ProfileFeedType.Feed
);
const { on: isNftGalleryEnabled } = useFeature(
FeatureFlag.NftGallery as string
const { on: isNftGalleryEnabled } = Growthbook.feature(
FeatureFlag.NftGallery
);

useEffect(() => {
Expand Down
6 changes: 3 additions & 3 deletions apps/web/src/components/Settings/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Sidebar from '@components/Shared/Sidebar';
import UserProfile from '@components/Shared/UserProfile';
import { useFeature } from '@growthbook/growthbook-react';
import {
AdjustmentsIcon,
BookmarkIcon,
Expand All @@ -12,6 +11,7 @@ import {
SparklesIcon,
UserIcon
} from '@heroicons/react/outline';
import { Growthbook } from '@lib/growthbook';
import { t, Trans } from '@lingui/macro';
import { FeatureFlag } from 'data';
import type { Profile } from 'lens';
Expand All @@ -20,8 +20,8 @@ import { useAppStore } from 'src/store/app';

const SettingsSidebar: FC = () => {
const currentProfile = useAppStore((state) => state.currentProfile);
const { on: isExportDataEnabled } = useFeature(
FeatureFlag.ExportData as string
const { on: isExportDataEnabled } = Growthbook.feature(
FeatureFlag.ExportData
);

return (
Expand Down
6 changes: 3 additions & 3 deletions apps/web/src/components/Shared/Footer/Locale.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useFeature } from '@growthbook/growthbook-react';
import { Menu } from '@headlessui/react';
import { GlobeAltIcon } from '@heroicons/react/outline';
import { Growthbook } from '@lib/growthbook';
import { setLocale, supportedLocales } from '@lib/i18n';
import { Mixpanel } from '@lib/mixpanel';
import { useLingui } from '@lingui/react';
Expand All @@ -13,8 +13,8 @@ import MenuTransition from '../MenuTransition';

const Locale: FC = () => {
const { i18n } = useLingui();
const { on: isGatedLocalesEnabled } = useFeature(
FeatureFlag.GatedLocales as string
const { on: isGatedLocalesEnabled } = Growthbook.feature(
FeatureFlag.GatedLocales
);
const gatedLocales = ['ta', 'es', 'ru', 'fr'];
const locales = Object.fromEntries(
Expand Down
19 changes: 19 additions & 0 deletions apps/web/src/lib/growthbook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { GrowthBook } from '@growthbook/growthbook';
import { GROWTHBOOK_KEY } from 'data';

const growthbook = new GrowthBook({
clientKey: GROWTHBOOK_KEY,
enableDevMode: false
});

export const Growthbook = {
init: async () => {
await growthbook.loadFeatures({ autoRefresh: true });
},
setAttributes: (attributes: Record<string, any>) => {
growthbook.setAttributes(attributes);
},
feature: (feature: string) => {
return { on: growthbook.isOn(feature) };
}
};
31 changes: 21 additions & 10 deletions apps/web/src/lib/uploadToIPFS.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { S3 } from '@aws-sdk/client-s3';
import { ThirdwebStorage } from '@thirdweb-dev/storage';
import axios from 'axios';
import { KillSwitch } from 'data';
import { EVER_API, S3_BUCKET, STS_TOKEN_URL } from 'data/constants';
import type { MediaSet } from 'lens';
import { v4 as uuid } from 'uuid';

import { Growthbook } from './growthbook';

const { on: useThirdwebIpfs } = Growthbook.feature(KillSwitch.UseThirdwebIpfs);
const FALLBACK_TYPE = 'image/jpeg';

/**
Expand Down Expand Up @@ -35,8 +40,20 @@ const getS3Client = async (): Promise<S3> => {
*/
const uploadToIPFS = async (data: any): Promise<MediaSet[]> => {
try {
const client = await getS3Client();
const files = Array.from(data);

if (useThirdwebIpfs) {
const storage = new ThirdwebStorage();
const uris = await storage.uploadBatch(files);

return uris.map((uri: string) => {
return {
original: { url: uri, mimeType: data.type || FALLBACK_TYPE }
};
});
}

const client = await getS3Client();
const attachments = await Promise.all(
files.map(async (_: any, i: number) => {
const file = data[i];
Expand Down Expand Up @@ -75,18 +92,12 @@ const uploadToIPFS = async (data: any): Promise<MediaSet[]> => {
*/
export const uploadFileToIPFS = async (file: File): Promise<MediaSet> => {
try {
const client = await getS3Client();
const params = {
Bucket: S3_BUCKET.LENSTER_MEDIA,
Key: uuid()
};
await client.putObject({ ...params, Body: file, ContentType: file.type });
const result = await client.headObject(params);
const metadata = result.Metadata;
const ipfsResponse = await uploadToIPFS([file]);
const metadata = ipfsResponse[0];

return {
original: {
url: `ipfs://${metadata?.['ipfs-hash']}`,
url: `ipfs://${metadata.original.url}`,
mimeType: file.type || FALLBACK_TYPE
}
};
Expand Down
4 changes: 4 additions & 0 deletions packages/data/feature-flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ export enum FeatureFlag {
ExportData = 'export-data',
Polls = 'polls'
}

export enum KillSwitch {
UseThirdwebIpfs = 'use-thirdweb-ipfs'
}
Loading