diff --git a/apps/mobile/src/App.tsx b/apps/mobile/src/App.tsx
index fb73279fb3..6df52aa8be 100644
--- a/apps/mobile/src/App.tsx
+++ b/apps/mobile/src/App.tsx
@@ -37,6 +37,7 @@ import ToastProvider from './contexts/ToastContext';
import { TokenStateManagerProvider } from './contexts/TokenStateManagerContext';
import { magic } from './magic';
import { useCacheIntroVideo } from './screens/Onboarding/useCacheIntroVideo';
+import SanityDataProvider from './contexts/SanityDataContext';
SplashScreen.preventAutoHideAsync();
@@ -157,28 +158,30 @@ export default function App() {
-
-
-
-
-
-
-
- {/* Register the user's push token if one exists (does not prompt the user) */}
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ {/* Register the user's push token if one exists (does not prompt the user) */}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/mobile/src/components/Mint/MintCampaign/MintCampaignBottomSheet.tsx b/apps/mobile/src/components/Mint/MintCampaign/MintCampaignBottomSheet.tsx
index 728d020efc..5c52b6f9b4 100644
--- a/apps/mobile/src/components/Mint/MintCampaign/MintCampaignBottomSheet.tsx
+++ b/apps/mobile/src/components/Mint/MintCampaign/MintCampaignBottomSheet.tsx
@@ -1,18 +1,48 @@
-import { MCHX_CLAIM_CODE_KEY } from 'src/constants/storageKeys';
+import { useMemo } from 'react';
import usePersistedState from 'src/hooks/usePersistedState';
+import { useSanityDataContext } from '~/contexts/SanityDataContext';
+
import MintCampaignPostTransaction from './MintCampaignPostTransaction';
import MintCampaignPreTransaction from './MintCampaignPreTransaction';
-export default function MintCampaignBottomSheet({ onClose }: { onClose: () => void }) {
+type Props = {
+ onClose?: () => void;
+ projectInternalId?: string;
+};
+
+export default function MintCampaignBottomSheet({ onClose, projectInternalId }: Props) {
// claimCode is the identifer used to poll for the status of the mint
// Once we kick off the mint, the backend returns a claim code from Highlight that we can use to check the status of the mint
- const [claimCode, setClaimCode] = usePersistedState(MCHX_CLAIM_CODE_KEY, '');
+ const [claimCode, setClaimCode] = usePersistedState(`${projectInternalId}_claim_code`, '');
+
+ const { data } = useSanityDataContext();
+ const projectData = useMemo(() => {
+ return data?.mintProjects.find((document) => document.internalId === projectInternalId);
+ }, [data, projectInternalId]);
+ console.log({ projectData });
+
+ if (!projectData) {
+ // TODO decide best way to handle missing data
+ return null;
+ }
if (claimCode) {
- return ;
+ return (
+
+ );
}
- return ;
+ return (
+
+ );
}
diff --git a/apps/mobile/src/components/Mint/MintCampaign/MintCampaignPostTransaction.tsx b/apps/mobile/src/components/Mint/MintCampaign/MintCampaignPostTransaction.tsx
index 4099032707..bc56ca7594 100644
--- a/apps/mobile/src/components/Mint/MintCampaign/MintCampaignPostTransaction.tsx
+++ b/apps/mobile/src/components/Mint/MintCampaign/MintCampaignPostTransaction.tsx
@@ -15,6 +15,7 @@ import { SpinnerIcon } from 'src/icons/SpinnerIcon';
import { Button } from '~/components/Button';
import { BaseM, TitleS } from '~/components/Text';
+import { MintProject } from '~/contexts/SanityDataContext';
import {
HighlightTxStatus,
MintCampaignPostTransactionMintStatusQuery,
@@ -26,9 +27,11 @@ import { NftDetailAsset } from '../../../screens/NftDetailScreen/NftDetailAsset/
export default function MintCampaignPostTransaction({
claimCode,
onClose,
+ projectData,
}: {
claimCode: string;
- onClose: () => void;
+ onClose?: () => void;
+ projectData: MintProject;
}) {
const [state, setState] = useState('TX_PENDING');
// TODO: Fix any - prioritizing merging atm
@@ -119,7 +122,9 @@ export default function MintCampaignPostTransaction({
});
}
- onClose();
+ if (onClose) {
+ onClose();
+ }
// close bottom sheet
}, [navigation, onClose, token?.dbid]);
@@ -129,7 +134,9 @@ export default function MintCampaignPostTransaction({
if (token?.definition?.community) {
navigateToCommunity(token?.definition?.community);
}
- onClose();
+ if (onClose) {
+ onClose();
+ }
}, [navigateToCommunity, onClose, token?.definition?.community]);
if (state === 'TOKEN_SYNCED' && token) {
@@ -137,7 +144,12 @@ export default function MintCampaignPostTransaction({
Congratulations!
- You collected {`${token?.definition?.name ?? 'Radiance'} by MCHX`}
+
+ You collected{' '}
+ {`${token?.definition?.name ?? projectData.collectionName} by ${
+ projectData.artistName
+ }`}
+
Thank you for using the Gallery mobile app. Share your unique piece with others below!
@@ -173,7 +185,7 @@ export default function MintCampaignPostTransaction({
{state === 'TX_PENDING'
? 'Your new artwork is being minted onchain. This should take less than a minute.'
- : 'Revealing your unique artwork. It will be ready to view in a moment!'}
+ : 'Revealing your artwork. It will be ready to view in a moment!'}
@@ -183,7 +195,7 @@ export default function MintCampaignPostTransaction({
size="s"
colorOverride={{ lightMode: colors.shadow, darkMode: colors.shadow }}
/>
-
+
{error && {error}}
@@ -191,22 +203,22 @@ export default function MintCampaignPostTransaction({
);
}
-const COPY = [
- 'Anton Dubrovin, aka MCHX, was born in Kazakhstan and is currently based in Georgia.',
- 'Anton is a digital artist known for experimenting with colors and form.',
- 'Anton uses color as a universal channel of emotional connection and self-exploration.',
- 'For this project, MCHX created over 60 unique color modes and used a circle as the central object due to its universal symbolism of unity and integrity.',
- 'This work leverages Javascript, GLSL, and Display P3 wide-gamut to explore emotional connection through color.',
- "Anton's diverse inspiration comes from 20th-century abstraction, Abstract Expressionism, Color Field artists, nature, music, and the internet.",
- 'In his free time, Anton enjoys taking walks, reading, and watching Japanese anime and dramas.',
- 'Anton has been creating art since 2016, but entered the NFT and Web3 space in 2020.',
- 'Anton believes in the exchange of energy inherent in blockchain interactions and his work carries imprints of his emotional states or needs at the time of creation.',
-];
+// const COPY = [
+// 'Anton Dubrovin, aka MCHX, was born in Kazakhstan and is currently based in Georgia.',
+// 'Anton is a digital artist known for experimenting with colors and form.',
+// 'Anton uses color as a universal channel of emotional connection and self-exploration.',
+// 'For this project, MCHX created over 60 unique color modes and used a circle as the central object due to its universal symbolism of unity and integrity.',
+// 'This work leverages Javascript, GLSL, and Display P3 wide-gamut to explore emotional connection through color.',
+// "Anton's diverse inspiration comes from 20th-century abstraction, Abstract Expressionism, Color Field artists, nature, music, and the internet.",
+// 'In his free time, Anton enjoys taking walks, reading, and watching Japanese anime and dramas.',
+// 'Anton has been creating art since 2016, but entered the NFT and Web3 space in 2020.',
+// 'Anton believes in the exchange of energy inherent in blockchain interactions and his work carries imprints of his emotional states or needs at the time of creation.',
+// ];
const FADE_DURATION = 250;
const TEXT_DURATION = 8000;
-function LoadingStateMessage() {
+function LoadingStateMessage({ funFacts }: { funFacts: string[] }) {
const [index, setIndex] = useState(0);
const fadeInOpacity = useSharedValue(1);
@@ -235,18 +247,18 @@ function LoadingStateMessage() {
const updateDisplayedMessage = async () => {
fadeOut();
await new Promise((resolve) => setTimeout(resolve, FADE_DURATION));
- setIndex((index) => (index + 1) % COPY.length);
+ setIndex((index) => (index + 1) % funFacts.length);
fadeIn();
};
const interval = setInterval(updateDisplayedMessage, TEXT_DURATION);
return () => clearInterval(interval);
- }, [fadeIn, fadeOut]);
+ }, [fadeIn, fadeOut, funFacts.length]);
return (
- {COPY[index]}
+ {funFacts[index]}
);
diff --git a/apps/mobile/src/components/Mint/MintCampaign/MintCampaignPreTransaction.tsx b/apps/mobile/src/components/Mint/MintCampaign/MintCampaignPreTransaction.tsx
index c6a0d26a3e..912115785d 100644
--- a/apps/mobile/src/components/Mint/MintCampaign/MintCampaignPreTransaction.tsx
+++ b/apps/mobile/src/components/Mint/MintCampaign/MintCampaignPreTransaction.tsx
@@ -2,25 +2,25 @@ import { Suspense, useCallback, useEffect, useMemo, useState } from 'react';
import { Image, View } from 'react-native';
import { graphql, useLazyLoadQuery } from 'react-relay';
import { contexts } from 'shared/analytics/constants';
-import { MCHX_CLAIM_CODE_KEY } from 'src/constants/storageKeys';
import { useHighlightClaimMint } from 'src/hooks/useHighlightClaimMint';
import usePersistedState from 'src/hooks/usePersistedState';
import { Button } from '~/components/Button';
import { BaseM, BaseS, TitleLItalic, TitleS } from '~/components/Text';
+import { MintProject } from '~/contexts/SanityDataContext';
import { MintCampaignPreTransactionQuery } from '~/generated/MintCampaignPreTransactionQuery.graphql';
-export const MCHX_MINT_CAMPAIGN_END_DATE = '2024-05-05T10:00:00-04:00';
-
-const MCHX_COLLECTION_ID = '660d4342c6bc04d5dc5598e7';
-
export default function MintCampaignPreTransaction({
setClaimCode,
+ projectInternalId,
+ projectData,
}: {
setClaimCode: (claimCode: string) => void;
+ projectInternalId: string;
+ projectData: MintProject;
}) {
const calculateTimeLeftText = useCallback(() => {
- const endDate = new Date(MCHX_MINT_CAMPAIGN_END_DATE).getTime();
+ const endDate = new Date(projectData.endDate).getTime();
const now = new Date().getTime();
const difference = endDate - now;
@@ -33,13 +33,13 @@ export default function MintCampaignPreTransaction({
}
return 'Campaign ended';
- }, []);
+ }, [projectData.endDate]);
const isMintOver = useMemo(() => {
- const endDate = new Date(MCHX_MINT_CAMPAIGN_END_DATE).getTime();
+ const endDate = new Date(projectData.endDate).getTime();
const now = new Date().getTime();
return now > endDate;
- }, []);
+ }, [projectData.endDate]);
const [timeLeft, setTimeLeft] = useState(calculateTimeLeftText());
const [error, setError] = useState('');
@@ -54,7 +54,7 @@ export default function MintCampaignPreTransaction({
const { claimMint, isClamingMint } = useHighlightClaimMint();
- const [, setClaimCodeLocalStorage] = usePersistedState(MCHX_CLAIM_CODE_KEY, '');
+ const [, setClaimCodeLocalStorage] = usePersistedState(`${projectInternalId}_claim_code`, '');
const handlePress = useCallback(
async (recipientWalletId: string) => {
@@ -64,7 +64,7 @@ export default function MintCampaignPreTransaction({
try {
const claimCode = await claimMint({
- collectionId: MCHX_COLLECTION_ID,
+ collectionId: projectData.highlightProjectId,
recipientWalletId,
});
@@ -84,20 +84,17 @@ export default function MintCampaignPreTransaction({
setError('Something went wrong while minting. Please try again.');
}
},
- [claimMint, setClaimCode, setClaimCodeLocalStorage]
+ [claimMint, projectData.highlightProjectId, setClaimCode, setClaimCodeLocalStorage]
);
return (
- Exclusive free mint
-
- Thank you for downloading the Gallery app. As a token of our gratitude, we invite you to
- mint Radiance by MCHX - on us ❤️
-
+ {projectData.title}
+ {projectData.description}
@@ -107,7 +104,7 @@ export default function MintCampaignPreTransaction({
Limit 1 per user
- Gallery x MCHX
+ Gallery x {projectData.artistName}
@@ -128,7 +125,7 @@ export default function MintCampaignPreTransaction({
{error && {error}}
- Note: Image above is an indicative preview only, final artwork will be uniquely generated.
+ Note: Image above is an indicative preview only, final artwork will be randomly generated.
Powered by highlight.xyz
diff --git a/apps/mobile/src/components/Notification/NotificationList.tsx b/apps/mobile/src/components/Notification/NotificationList.tsx
index 9e95a63a29..79cf228000 100644
--- a/apps/mobile/src/components/Notification/NotificationList.tsx
+++ b/apps/mobile/src/components/Notification/NotificationList.tsx
@@ -69,7 +69,7 @@ export function NotificationList({ queryRef }: Props) {
queryRef
);
- const { announcement, fetchAnnouncement } = useAnnouncementContext();
+ const { announcement, fetchAnnouncement, hasDismissedAnnouncement } = useAnnouncementContext();
const clearNotifications = useMobileClearNotifications();
const { isRefreshing, handleRefresh } = useRefreshHandle(refetch);
@@ -83,14 +83,14 @@ export function NotificationList({ queryRef }: Props) {
}
}
- if (announcement && announcement.active) {
+ if (announcement && announcement.active && !hasDismissedAnnouncement) {
notifications.push({ id: 'announcement', kind: 'announcement' });
}
notifications.reverse();
return notifications;
- }, [announcement, query]);
+ }, [announcement, hasDismissedAnnouncement, query]);
const loadMore = useCallback(() => {
if (hasPrevious) {
diff --git a/apps/mobile/src/components/Notification/Notifications/AnnouncementNotification.tsx b/apps/mobile/src/components/Notification/Notifications/AnnouncementNotification.tsx
index a0ba56e53f..db6f524807 100644
--- a/apps/mobile/src/components/Notification/Notifications/AnnouncementNotification.tsx
+++ b/apps/mobile/src/components/Notification/Notifications/AnnouncementNotification.tsx
@@ -3,16 +3,27 @@ import { useCallback, useEffect } from 'react';
import { View } from 'react-native';
import FastImage from 'react-native-fast-image';
import { contexts } from 'shared/analytics/constants';
+import colors from 'shared/theme/colors';
+import { XMarkIcon } from 'src/icons/XMarkIcon';
-import { Button } from '~/components/Button';
import { GalleryTouchableOpacity } from '~/components/GalleryTouchableOpacity';
+import MintCampaignBottomSheet from '~/components/Mint/MintCampaign/MintCampaignBottomSheet';
import { BaseM } from '~/components/Text';
import { useAnnouncementContext } from '~/contexts/AnnouncementContext';
+import { useBottomSheetModalActions } from '~/contexts/BottomSheetModalContext';
-// display announcement content from Sanity
+// Displays announcement content from Sanity
export default function AnnouncementNotification() {
- const { announcement, markAnnouncementAsSeen } = useAnnouncementContext();
- const handlePress = useCallback(() => {}, []);
+ const { announcement, markAnnouncementAsSeen, dismissAnnouncement } = useAnnouncementContext();
+ const { showBottomSheetModal } = useBottomSheetModalActions();
+ const handlePress = useCallback(() => {
+ showBottomSheetModal({
+ content: ,
+ });
+ }, [announcement?.internal_id, showBottomSheetModal]);
+ const handleDismissPress = useCallback(() => {
+ dismissAnnouncement();
+ }, [dismissAnnouncement]);
useEffect(() => {
markAnnouncementAsSeen();
@@ -25,10 +36,10 @@ export default function AnnouncementNotification() {
}
return (
-
+
- {announcement.title}
- {announcement.description}
+
+ {announcement.title}
+
+ {announcement.description}
- {announcement.ctaText && (
-
- )}
+
+
+
);
diff --git a/apps/mobile/src/contexts/AnnouncementContext.tsx b/apps/mobile/src/contexts/AnnouncementContext.tsx
index 5ff633ffad..50d2c972c4 100644
--- a/apps/mobile/src/contexts/AnnouncementContext.tsx
+++ b/apps/mobile/src/contexts/AnnouncementContext.tsx
@@ -10,6 +10,7 @@ import {
} from 'react';
import { useReportError } from 'shared/contexts/ErrorReportingContext';
import { fetchSanityContent } from 'src/utils/sanity';
+import { useEffectOnAppForeground } from 'src/utils/useEffectOnAppForeground';
type Announcement = {
internal_id: string;
@@ -26,7 +27,9 @@ type AnnouncementContextType = {
announcement: Announcement | null;
fetchAnnouncement: () => void;
hasSeenAnnouncement: boolean;
+ hasDismissedAnnouncement: boolean;
markAnnouncementAsSeen: () => void;
+ dismissAnnouncement: () => void;
};
const AnnouncementContext = createContext(undefined);
@@ -81,7 +84,6 @@ export const AnnouncementProvider = ({ children }: { children: ReactNode[] }) =>
title,
description,
"imageUrl": image.asset->url,
- ctaText,
platform,
min_mobile_version
} | order(_createdAt desc)[0]`
@@ -100,6 +102,8 @@ export const AnnouncementProvider = ({ children }: { children: ReactNode[] }) =>
}
}, [checkDismissalStatus, checkSeenStatus, reportError]);
+ useEffectOnAppForeground(fetchAnnouncement);
+
// Function to dismiss an announcement
const dismissAnnouncement = useCallback(async () => {
if (announcement && announcement.internal_id) {
diff --git a/apps/mobile/src/contexts/SanityDataContext.tsx b/apps/mobile/src/contexts/SanityDataContext.tsx
new file mode 100644
index 0000000000..d48e0a583b
--- /dev/null
+++ b/apps/mobile/src/contexts/SanityDataContext.tsx
@@ -0,0 +1,89 @@
+import {
+ createContext,
+ ReactNode,
+ useCallback,
+ useContext,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react';
+import { fetchSanityContent } from 'src/utils/sanity';
+import { useEffectOnAppForeground } from 'src/utils/useEffectOnAppForeground';
+
+export type MintProject = {
+ name: string;
+ internalId: string;
+ startDate: string;
+ endDate: string;
+ highlightProjectId: string;
+ previewImageUrl: string;
+ artistName: string;
+ collectionName: string;
+ title: string;
+ description: string;
+ funFacts: string[];
+ active: boolean;
+};
+
+type sanityDocumentTypes = {
+ mintProjects: MintProject[];
+};
+
+type SanityDataContextType = {
+ data: sanityDocumentTypes | null;
+};
+
+const SanityDataContext = createContext(undefined);
+
+export function useSanityDataContext() {
+ const value = useContext(SanityDataContext);
+ if (!value) {
+ throw new Error('Tried to use SanityDataContext without a Provider');
+ }
+ return value;
+}
+
+export default function SanityDataProvider({ children }: { children: ReactNode }) {
+ const [data, setData] = useState(null);
+ const fetchData = useCallback(async () => {
+ console.log('fetching');
+ try {
+ const result = await fetchSanityContent(`
+ *[_type == "mintProject"] {
+ name,
+ internalId,
+ startDate,
+ endDate,
+ highlightProjectId,
+ "previewImageUrl": previewImage.asset->url,
+ artistName,
+ collectionName,
+ title,
+ description,
+ funFacts,
+ active
+ }`);
+ if (result) {
+ setData({ mintProjects: result });
+ }
+ } catch (error) {
+ console.error(error);
+ }
+ }, []);
+
+ useEffectOnAppForeground(fetchData);
+
+ useEffect(() => {
+ fetchData();
+ // Only run once
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ const value = useMemo(() => {
+ return {
+ data,
+ };
+ }, [data]);
+
+ return {children};
+}
diff --git a/apps/mobile/src/screens/SettingsScreen/DebugBottomSheetModal.tsx b/apps/mobile/src/screens/SettingsScreen/DebugBottomSheetModal.tsx
index 308418cabc..a72fd5899e 100644
--- a/apps/mobile/src/screens/SettingsScreen/DebugBottomSheetModal.tsx
+++ b/apps/mobile/src/screens/SettingsScreen/DebugBottomSheetModal.tsx
@@ -27,6 +27,7 @@ export default function DebugBottomSheetModal() {
MARFA_2023_SUBMITTED_FORM_KEY,
MCHX_CLAIM_CODE_KEY,
`hasSeenAnnouncement-oxen-farcon-2024`,
+ `hasDismissedAnnouncement-oxen-farcon-2024`,
]);
}, []);
return (