Skip to content

Commit

Permalink
[issue-1096] Mission pools feature
Browse files Browse the repository at this point in the history
  • Loading branch information
dominhquang committed Oct 31, 2023
1 parent c1c9eb0 commit 7b62eb7
Show file tree
Hide file tree
Showing 39 changed files with 1,204 additions and 46 deletions.
8 changes: 7 additions & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,8 @@ PODS:
- React-jsinspector (0.72.5)
- React-logger (0.72.5):
- glog
- react-native-blur (4.3.2):
- React-Core
- react-native-camera (4.2.1):
- React-Core
- react-native-camera/RCT (= 4.2.1)
Expand Down Expand Up @@ -682,6 +684,7 @@ DEPENDENCIES:
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- "react-native-blur (from `../node_modules/@react-native-community/blur`)"
- react-native-camera (from `../node_modules/react-native-camera`)
- "react-native-cameraroll (from `../node_modules/@react-native-camera-roll/camera-roll`)"
- react-native-config (from `../node_modules/react-native-config`)
Expand Down Expand Up @@ -807,6 +810,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/jsinspector"
React-logger:
:path: "../node_modules/react-native/ReactCommon/logger"
react-native-blur:
:path: "../node_modules/@react-native-community/blur"
react-native-camera:
:path: "../node_modules/react-native-camera"
react-native-cameraroll:
Expand Down Expand Up @@ -955,6 +960,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: ff70a72027dea5cc7d71cfcc6fad7f599f63987a
React-jsinspector: aef73cbd43b70675f572214d10fa438c89bf11ba
React-logger: 2e4aee3e11b3ec4fa6cfd8004610bbb3b8d6cca4
react-native-blur: cfdad7b3c01d725ab62a8a729f42ea463998afa2
react-native-camera: 3eae183c1d111103963f3dd913b65d01aef8110f
react-native-cameraroll: fad943a324a4d893c249cabe6d0608c807e0e58f
react-native-config: 86038147314e2e6d10ea9972022aa171e6b1d4d8
Expand Down Expand Up @@ -1017,4 +1023,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: d2e75413a9d4d28b9ab6ee8ae7baea6ba4324a25

COCOAPODS: 1.13.0
COCOAPODS: 1.12.1
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
},
"dependencies": {
"@coinbase/cbpay-js": "^1.7.0",
"react-native-fs": "^2.20.0",
"@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-regular-svg-icons": "^6.2.1",
Expand All @@ -43,6 +42,7 @@
"@react-native-async-storage/async-storage": "^1.17.11",
"@react-native-camera-roll/camera-roll": "^5.2.4",
"@react-native-clipboard/clipboard": "^1.11.1",
"@react-native-community/blur": "^4.3.2",
"@react-native-community/netinfo": "^9.3.7",
"@react-native-community/segmented-control": "^2.2.2",
"@react-native-community/slider": "^4.4.2",
Expand Down Expand Up @@ -87,8 +87,8 @@
"react-native-dynamic-tab-view": "^1.0.7-0",
"react-native-elements": "^3.4.3",
"react-native-error-boundary": "^1.2.3",
"react-native-static-server": "^0.5.0",
"react-native-fast-image": "^8.6.3",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "^2.9.0",
"react-native-image-picker": "^5.0.1",
"react-native-image-slider-box": "^2.0.7",
Expand All @@ -110,6 +110,7 @@
"react-native-screens": "^3.19.0",
"react-native-sensitive-info": "^6.0.0-alpha.9",
"react-native-splash-screen": "^3.3.0",
"react-native-static-server": "^0.5.0",
"react-native-status-bar-height": "^2.6.0",
"react-native-svg": "^13.6.0",
"react-native-svg-transformer": "^1.0.0",
Expand Down
4 changes: 3 additions & 1 deletion src/AppNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { GeneralSettings } from 'screens/Settings/General';
import { SendFund } from 'screens/Transaction/SendFundV2';
import { BrowserSearch } from 'screens/Home/Browser/BrowserSearch';
import { BrowserTabsManager } from 'screens/Home/Browser/BrowserTabsManager';
import { BrowserListByTabview } from 'screens/Home/Browser/BrowserListByTabview';
import { AccountsScreen } from 'screens/Account/AccountsScreen';
import CreateMasterPassword from 'screens/MasterPassword/CreateMasterPassword';
import { CreateAccount } from 'screens/Account/CreateAccount';
Expand Down Expand Up @@ -83,6 +82,8 @@ import { updateIsDeepLinkConnect } from 'stores/base/Settings';
import queryString from 'querystring';
import { connectWalletConnect } from 'utils/walletConnect';
import { useToast } from 'react-native-toast-notifications';
import { BrowserListByTabview } from 'screens/Home/Browser/BrowserListByTabview';
import { MissionPoolsByTabview } from 'screens/Home/Browser/MissionPool';

interface Props {
isAppReady: boolean;
Expand Down Expand Up @@ -453,6 +454,7 @@ const AppNavigator = ({ isAppReady }: Props) => {
<Stack.Screen name="BrowserSearch" component={BrowserSearch} />
<Stack.Screen name="BrowserTabsManager" component={BrowserTabsManager} />
<Stack.Screen name="BrowserListByTabview" component={BrowserListByTabview} />
<Stack.Screen name="MissionPoolsByTabview" component={MissionPoolsByTabview} />
<Stack.Screen name="AccountsScreen" component={AccountsScreen} />
<Stack.Screen name="Drawer" component={DrawerScreen} options={{ gestureEnabled: false }} />
</Stack.Group>
Expand Down
3 changes: 3 additions & 0 deletions src/components/MetaInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
StatusItem,
TotalItem,
TransferItem,
TextItem,
} from './parts';
import { InfoItemGeneralProps } from 'components/MetaInfo/types';
import { StyleProp, View } from 'react-native';
Expand Down Expand Up @@ -79,6 +80,7 @@ type CompoundedComponent = React.ForwardRefExoticComponent<Props> & {
Chain: typeof ChainItem;
DisplayType: typeof DisplayTypeItem;
Number: typeof NumberItem;
Text: typeof TextItem;
Total: typeof TotalItem;
Default: typeof DefaultItem;
};
Expand All @@ -93,6 +95,7 @@ MetaInfo.Transfer = TransferItem;
MetaInfo.Chain = ChainItem;
MetaInfo.DisplayType = DisplayTypeItem;
MetaInfo.Number = NumberItem;
MetaInfo.Text = TextItem;
MetaInfo.Total = TotalItem;
MetaInfo.Default = DefaultItem;

Expand Down
59 changes: 59 additions & 0 deletions src/components/MetaInfo/parts/TextItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { useMemo } from 'react';

import { InfoItemBase, SchemeColor } from '../types';
import { useSubWalletTheme } from 'hooks/useSubWalletTheme';
import MetaInfoStyles from 'components/MetaInfo/style';
import useGeneralStyles from 'components/MetaInfo/hooks/useGeneralStyles';
import { View } from 'react-native';
import { getSchemaColor, renderColContent } from 'components/MetaInfo/shared';
import { ActivityIndicator, Typography } from 'components/design-system-ui';
import { TextSizeProps } from 'components/design-system-ui/typography';
import { FontMedium, FontSemiBold } from 'styles/sharedStyles';

export interface TextInfoItem extends Omit<InfoItemBase, 'valueColorSchema'> {
value: string;
valueColorSchema?: SchemeColor;
valueFontWeight?: 'regular' | 'semibold';
valueSize?: TextSizeProps;
ellipsis?: boolean;
}

const TextItem: React.FC<TextInfoItem> = ({
label,
value,
valueColorSchema,
valueFontWeight,
loading,
valueSize,
ellipsis,
}: TextInfoItem) => {
const theme = useSubWalletTheme().swThemes;
const _style = MetaInfoStyles(theme);
const { labelGeneralStyle, valueGeneralStyle } = useGeneralStyles(theme);

const valueStyle = useMemo(() => {
return {
..._style.value,
...valueGeneralStyle,
...(valueColorSchema && { color: getSchemaColor(valueColorSchema, theme) }),
...(valueFontWeight === 'semibold' ? FontSemiBold : FontMedium),
};
}, [_style.value, theme, valueColorSchema, valueFontWeight, valueGeneralStyle]);

return (
<View style={_style.row}>
<View style={[_style.col]}>{renderColContent(label, { ..._style.label, ...labelGeneralStyle })}</View>
<View style={[_style.col, _style['col.grow'], _style['col.to-right']]}>
{loading ? (
<ActivityIndicator size={20} />
) : (
<Typography.Text style={valueStyle} size={valueSize} ellipsis={ellipsis}>
{value}
</Typography.Text>
)}
</View>
</View>
);
};

export default TextItem;
1 change: 1 addition & 0 deletions src/components/MetaInfo/parts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export { default as DataItem } from './DataItem';
export { default as DefaultItem } from './DefaultItem';
export { default as DisplayTypeItem } from './DisplayTypeItem';
export { default as NumberItem } from './NumberItem';
export { default as TextItem } from './TextItem';
export { default as StatusItem } from './StatusItem';
export { default as TotalItem } from './TotalItem';
export { default as TransferItem } from './TransferItem';
2 changes: 1 addition & 1 deletion src/components/MetaInfo/shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function getSchemaColor(schema: SchemeColor, theme: ThemeTypes) {
return theme.colorWarning;
}

return theme.colorTextLight2;
return theme.colorTextLight1;
}

export function renderColContent(
Expand Down
2 changes: 0 additions & 2 deletions src/components/MetaInfo/style/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,8 @@ export default (theme: ThemeTypes) =>
textAlign: 'left',
},
value: {
...FontMedium,
fontSize: theme.fontSize,
lineHeight: theme.lineHeight * theme.fontSize,
fontWeight: theme.bodyFontWeight,
},
valueWrapper: {
flexDirection: 'row',
Expand Down
51 changes: 51 additions & 0 deletions src/components/MissionPoolHorizontalItem/MissionPoolFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import { Linking, StyleProp, View, ViewStyle } from 'react-native';
import { Button, Icon } from 'components/design-system-ui';
import { GlobeHemisphereWest, PlusCircle, TwitterLogo } from 'phosphor-react-native';
import { useSubWalletTheme } from 'hooks/useSubWalletTheme';
import { MissionInfo } from 'types/missionPool';
import i18n from 'utils/i18n/i18n';

interface Props {
data: MissionInfo;
style: StyleProp<ViewStyle>;
closeDetailModal?: () => void;
}

export const MissionPoolFooter = ({ data, style, closeDetailModal }: Props) => {
const theme = useSubWalletTheme().swThemes;

const onPressJoinNow = async (url: string) => {
const transformUrl = `subwallet://browser?url=${encodeURIComponent(url)}`;
closeDetailModal && closeDetailModal();
Linking.openURL(transformUrl);
};

return (
<View style={style}>
<Button
style={{ borderWidth: 2, borderColor: theme.colorBgBorder }}
icon={<Icon phosphorIcon={GlobeHemisphereWest} size={'sm'} weight={'fill'} />}
size={'xs'}
shape={'circle'}
type={'secondary'}
onPress={() => data.campaign_url && Linking.openURL(data.campaign_url)}
/>
<Button
style={{ borderWidth: 2, borderColor: theme.colorBgBorder }}
icon={<Icon phosphorIcon={TwitterLogo} size={'sm'} weight={'fill'} />}
size={'xs'}
shape={'circle'}
type={'secondary'}
onPress={() => data.twitter_url && Linking.openURL(data.twitter_url)}
/>
<Button
icon={<Icon phosphorIcon={PlusCircle} size={'sm'} weight={'fill'} />}
size={'xs'}
shape={'round'}
onPress={() => onPressJoinNow(data.url)}>
{i18n.buttonTitles.joinNow}
</Button>
</View>
);
};
39 changes: 39 additions & 0 deletions src/components/MissionPoolHorizontalItem/MissionPoolTag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import capitalize from '@subwallet/react-ui/es/_util/capitalize';
import { MagicWand } from 'phosphor-react-native';
import { Icon, Tag } from 'components/design-system-ui';
import { MissionInfo } from 'types/missionPool';
import { useSubWalletTheme } from 'hooks/useSubWalletTheme';
import { useMissionPools } from 'hooks/useMissionPools';

interface Props {
data: MissionInfo;
}

export const MissionPoolTag = ({ data }: Props) => {
const theme = useSubWalletTheme().swThemes;
const { tagMap } = useMissionPools(data);
if (!data.tags || !data.tags.length) {
return null;
}
const tagSlug = data.tags[0];

let textColor = tagMap[tagSlug]?.theme || 'gray';
let _theme = tagMap[tagSlug]?.theme || 'gray';
if (tagMap[tagSlug]?.theme && ['success', 'warning', 'error'].includes(tagMap[tagSlug]?.theme)) {
_theme = `color${capitalize(tagMap[tagSlug]?.theme)}`;
}
const name = tagMap[tagSlug]?.name || capitalize(tagSlug.replace('_', ' '));
const iconWeight = tagMap[tagSlug]?.iconWeight;
const icon = tagMap[tagSlug]?.icon || MagicWand;

return (
<Tag
shape={'round'}
icon={<Icon size={'xs'} phosphorIcon={icon} weight={iconWeight} iconColor={theme[_theme]} />}
bgType={'default'}
color={textColor}>
{name}
</Tag>
);
};
71 changes: 71 additions & 0 deletions src/components/MissionPoolHorizontalItem/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import { TouchableOpacity, View } from 'react-native';
import { Image, Typography } from 'components/design-system-ui';
import { BlurView } from '@react-native-community/blur';
import { IconWeight } from 'phosphor-react-native';
import { MissionInfo } from 'types/missionPool';
import { useSubWalletTheme } from 'hooks/useSubWalletTheme';
import { SWIconProps } from 'components/design-system-ui/icon';
import createStyles from './style';
import { FontSemiBold } from 'styles/sharedStyles';
import { BUTTON_ACTIVE_OPACITY } from 'constants/index';
import { useMissionPools } from 'hooks/useMissionPools';
import { MissionPoolTag } from 'components/MissionPoolHorizontalItem/MissionPoolTag';
import { MissionPoolFooter } from 'components/MissionPoolHorizontalItem/MissionPoolFooter';

export enum TagType {
FCFS = 'fcfs',
POINTS = 'points',
LUCKY_DRAW = 'lucky_draw',
MANUAL_SELECTION = 'manual_selection',
}

export type TagInfo = {
theme: string;
name: string;
slug: string;
icon: SWIconProps['phosphorIcon'];
iconWeight?: IconWeight;
};

interface Props {
data: MissionInfo;
onPressItem: () => void;
}

export const MissionPoolHorizontalItem = ({ data, onPressItem }: Props) => {
const theme = useSubWalletTheme().swThemes;
const styles = createStyles(theme);
const { timeline } = useMissionPools(data);

return (
<TouchableOpacity activeOpacity={BUTTON_ACTIVE_OPACITY} onPress={onPressItem} style={styles.missionItemWrapper}>
<Image key={'blurryImage'} src={{ uri: data.backdrop_image }} style={styles.backdropImgStyle} />
<BlurView style={styles.backdropImgBlurView} blurType={'dark'} blurAmount={10} />
<View style={styles.missionItemContent}>
<Image src={{ uri: data.logo }} style={{ width: 64, height: 64 }} />
<Typography.Text size={'lg'} ellipsis style={styles.missionItemName}>
{data.name}
</Typography.Text>
<View style={styles.missionItemRow}>
<Typography.Text style={{ color: theme.colorTextTertiary, ...FontSemiBold }}>{'Rewards:'}</Typography.Text>
<Typography.Text style={{ color: theme.colorSuccess, ...FontSemiBold }}>{data.reward}</Typography.Text>
</View>
<Typography.Text ellipsis numberOfLines={2} size={'sm'} style={styles.missionItemDescription}>
{data.description}
</Typography.Text>
<View style={[styles.missionItemRow, { paddingBottom: theme.padding }]}>
<Typography.Text style={{ color: theme.colorTextTertiary, ...FontSemiBold }}>{'Timeline:'}</Typography.Text>
<Typography.Text ellipsis style={styles.missionItemTimeline}>
{timeline}
</Typography.Text>
</View>
<MissionPoolTag data={data} />
<MissionPoolFooter
data={data}
style={{ flexDirection: 'row', paddingTop: theme.paddingXXL - 8, gap: theme.padding }}
/>
</View>
</TouchableOpacity>
);
};
Loading

0 comments on commit 7b62eb7

Please sign in to comment.