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

Feature/asc 19495 update community #14

Merged
merged 15 commits into from
Jan 30, 2024
Merged
38 changes: 38 additions & 0 deletions src/components/ChooseCategoryModal/Components/RenderCategories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Image, Text, TouchableOpacity } from 'react-native';
import React from 'react';
import useImage from '../../../hooks/useImage';
import { SvgXml } from 'react-native-svg';
import { categoryIcon } from '../../../svg/svg-xml-list';
import { useStyle } from '../styles';

const RenderCategories = ({
item,
onSelectCategory,
}: {
item: Amity.Category;
onSelectCategory: (id: string, name: string) => void;
}) => {
const avatarURL = useImage({ fileId: item.avatarFileId });
const styles = useStyle();
return (
<TouchableOpacity
onPress={() => onSelectCategory(item.categoryId, item.name)}
style={styles.rowContainer}
>
{item.avatarFileId ? (
<Image
style={styles.avatar}
source={{
uri: avatarURL,
}}
/>
) : (
<SvgXml xml={categoryIcon} width={40} height={40} />
)}

<Text style={styles.communityText}>{item.name}</Text>
</TouchableOpacity>
);
};

export default RenderCategories;
51 changes: 21 additions & 30 deletions src/components/ChooseCategoryModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,32 @@ import {
View,
Text,
Modal,
Image,
FlatList,
type NativeSyntheticEvent,
type NativeScrollEvent,
} from 'react-native';
import { SvgXml } from 'react-native-svg';
import { categoryIcon, closeIcon } from '../../svg/svg-xml-list';
import useAuth from '../../hooks/useAuth';
import { getStyles } from './styles';
import { closeIcon } from '../../svg/svg-xml-list';
import { useStyle } from './styles';
import { useTheme } from 'react-native-paper';
import type { MyMD3Theme } from 'src/providers/amity-ui-kit-provider';
import RenderCategories from './Components/RenderCategories';

interface IModal {
visible: boolean;
userId?: string;
onClose: () => void;
onSelect: (categoryId: string, categoryName: string) => void;
categoryId?: string;
}
const ChooseCategoryModal = ({ visible, onClose, onSelect }: IModal) => {
const ChooseCategoryModal = ({
visible,
onClose,
onSelect,
categoryId,
}: IModal) => {
const theme = useTheme() as MyMD3Theme;
const styles = getStyles();
const { apiRegion } = useAuth();
const styles = useStyle();
const [categories, setCategories] =
useState<Amity.LiveCollection<Amity.Category>>();
const { data: categoriesList, onNextPage } = categories ?? {};
Expand All @@ -40,6 +44,12 @@ const ChooseCategoryModal = ({ visible, onClose, onSelect }: IModal) => {
(data: Amity.LiveCollection<Amity.Category>) => {
if (data) {
setCategories(data);
if (categoryId) {
const currentCategoryName =
data.data.find((item) => item.categoryId === categoryId)
?.name ?? '';
onSelect(categoryId, currentCategoryName);
}
}
}
);
Expand All @@ -50,34 +60,13 @@ const ChooseCategoryModal = ({ visible, onClose, onSelect }: IModal) => {
};

loadCategories();
}, []);
}, [categoryId, onSelect]);

const onSelectCategory = (categoryId: string, categoryName: string) => {
onSelect && onSelect(categoryId, categoryName);
unSubFunc && unSubFunc();
onClose && onClose();
};
const renderCategories = ({ item }: { item: Amity.Category }) => {
return (
<TouchableOpacity
onPress={() => onSelectCategory(item.categoryId, item.name)}
style={styles.rowContainer}
>
{item.avatarFileId ? (
<Image
style={styles.avatar}
source={{
uri: `https://api.${apiRegion}.amity.co/api/v3/files/${item.avatarFileId}/download`,
}}
/>
) : (
<SvgXml xml={categoryIcon} width={40} height={40} />
)}

<Text style={styles.communityText}>{item.name}</Text>
</TouchableOpacity>
);
};

const handleScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
const scrollPosition = event.nativeEvent.contentOffset.y;
Expand Down Expand Up @@ -112,7 +101,9 @@ const ChooseCategoryModal = ({ visible, onClose, onSelect }: IModal) => {
</View>
<FlatList
data={categoriesList}
renderItem={renderCategories}
renderItem={({ item }) => (
<RenderCategories item={item} onSelectCategory={onSelectCategory} />
)}
keyExtractor={(item) => item.categoryId}
onScroll={handleScroll}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ChooseCategoryModal/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Platform, StyleSheet } from 'react-native';
import { useTheme } from 'react-native-paper';
import type { MyMD3Theme } from 'src/providers/amity-ui-kit-provider';

export const getStyles = () => {
export const useStyle = () => {
const theme = useTheme() as MyMD3Theme;

const styles = StyleSheet.create({
Expand Down
81 changes: 81 additions & 0 deletions src/components/MyCommunity/Components/CommunityList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { Image, Text, TouchableOpacity, View } from 'react-native';
import React from 'react';
import { SvgXml } from 'react-native-svg';
import {
communityIcon,
officialIcon,
privateIcon,
} from '../../../svg/svg-xml-list';
import { useStyle } from '../styles';
import useImage from '../../../hooks/useImage';
import type { MyMD3Theme } from '../../../providers/amity-ui-kit-provider';
import { useTheme } from 'react-native-paper';

interface ICommunityItems {
communityId: string;
avatarFileId: string;
displayName: string;
isPublic: boolean;
isOfficial: boolean;
}

const CommunityList = ({
item,
onClickItem,
}: {
item: ICommunityItems;
onClickItem: (id: string, name: string) => void;
}) => {
const MAX_LENGTH = 6;
const theme = useTheme() as MyMD3Theme;
const styles = useStyle();
const avatarUrl = useImage({ fileId: item.avatarFileId });
const getDisplayName = (text: string, type: string) => {
if (text) {
const reduceLetter = type === 'private' ? 3 : 0;
if (text!.length > MAX_LENGTH - reduceLetter) {
return text!.substring(0, MAX_LENGTH) + '...';
}
return text;
}
return 'Display name';
};
NaingAmity marked this conversation as resolved.
Show resolved Hide resolved
return (
<TouchableOpacity
onPress={() => onClickItem(item.communityId, item.displayName)}
key={item.communityId}
style={styles.itemContainer}
>
{item.avatarFileId ? (
<Image source={{ uri: avatarUrl }} style={styles.avatar} />
) : (
<SvgXml
style={styles.avatar}
width={40}
height={40}
xml={communityIcon}
/>
)}
<View style={styles.textRow}>
{!item.isPublic && (
<SvgXml width={17} height={17} xml={privateIcon(theme.colors.base)} />
)}
<Text style={styles.itemText}>
{getDisplayName(
item.displayName,
!item.isPublic ? 'private' : 'public'
NaingAmity marked this conversation as resolved.
Show resolved Hide resolved
)}
</Text>
{item.isOfficial && (
<SvgXml
width={20}
height={20}
xml={officialIcon(theme.colors.primary)}
/>
)}
</View>
</TouchableOpacity>
);
};

export default CommunityList;
87 changes: 17 additions & 70 deletions src/components/MyCommunity/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import React, { useEffect, useState } from 'react';
import { View, Text, ScrollView, Image, TouchableOpacity } from 'react-native';
import { getStyles } from './styles';
import React, { useCallback, useState } from 'react';
import { View, Text, ScrollView, TouchableOpacity } from 'react-native';
import { useStyle } from './styles';
import { CommunityRepository } from '@amityco/ts-sdk-react-native';
import {
arrowOutlined,
communityIcon,
officialIcon,
privateIcon,
} from '../../svg/svg-xml-list';
import { arrowOutlined } from '../../svg/svg-xml-list';
import { SvgXml } from 'react-native-svg';
import { useNavigation } from '@react-navigation/native';
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import useAuth from '../../hooks/useAuth';
import type { MyMD3Theme } from '../../providers/amity-ui-kit-provider';
import { useTheme } from 'react-native-paper';
import CommunityList from './Components/CommunityList';

interface ICommunityItems {
communityId: string;
Expand All @@ -24,14 +19,9 @@ interface ICommunityItems {
}
export default function MyCommunity() {
const theme = useTheme() as MyMD3Theme;
const styles = getStyles();
const { apiRegion } = useAuth();
const maxLength = 6;
const styles = useStyle();
const [communityItems, setCommunityItems] = useState<ICommunityItems[]>([]);
const navigation = useNavigation<NativeStackNavigationProp<any>>();
const avatarFileURL = (fileId: string) => {
return `https://api.${apiRegion}.amity.co/api/v3/files/${fileId}/download?size=medium`;
};
const queryCommunities = () => {
const unsubscribe = CommunityRepository.getCommunities(
{ membership: 'member', limit: 8 },
Expand All @@ -52,19 +42,12 @@ export default function MyCommunity() {
);
unsubscribe();
};
const getDisplayName = (text: string, type: string) => {
if (text) {
const reduceLetter = type === 'private' ? 3 : 0;
if (text!.length > maxLength - reduceLetter) {
return text!.substring(0, maxLength) + '...';
}
return text;
}
return 'Display name';
};
useEffect(() => {
queryCommunities();
}, []);

useFocusEffect(
useCallback(() => {
queryCommunities();
NaingAmity marked this conversation as resolved.
Show resolved Hide resolved
}, [])
);

const onClickItem = (communityId: string, displayName: string) => {
navigation.navigate('CommunityHome', {
Expand Down Expand Up @@ -95,47 +78,11 @@ export default function MyCommunity() {
contentContainerStyle={styles.scrollView}
>
{communityItems.map((item) => (
<TouchableOpacity
onPress={() => onClickItem(item.communityId, item.displayName)}
<CommunityList
key={item.communityId}
style={styles.itemContainer}
>
{item.avatarFileId ? (
<Image
source={{ uri: avatarFileURL(item.avatarFileId) }}
style={styles.avatar}
/>
) : (
<SvgXml
style={styles.avatar}
width={40}
height={40}
xml={communityIcon}
/>
)}
<View style={styles.textRow}>
{!item.isPublic && (
<SvgXml
width={17}
height={17}
xml={privateIcon(theme.colors.base)}
/>
)}
<Text style={styles.itemText}>
{getDisplayName(
item.displayName,
!item.isPublic ? 'private' : 'public'
)}
</Text>
{item.isOfficial && (
<SvgXml
width={20}
height={20}
xml={officialIcon(theme.colors.primary)}
/>
)}
</View>
</TouchableOpacity>
item={item}
onClickItem={onClickItem}
/>
))}
<TouchableOpacity onPress={onClickSeeAll} style={styles.seeAllBtn}>
<View style={styles.seeAllIcon}>
Expand Down
2 changes: 1 addition & 1 deletion src/components/MyCommunity/styles.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { StyleSheet } from 'react-native';
import { useTheme } from 'react-native-paper';
import type { MyMD3Theme } from 'src/providers/amity-ui-kit-provider';
export const getStyles = () => {
export const useStyle = () => {
const theme = useTheme() as MyMD3Theme;

const styles = StyleSheet.create({
Expand Down
31 changes: 31 additions & 0 deletions src/hooks/useImage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useEffect, useState } from 'react';
import { FileRepository } from '@amityco/ts-sdk-react-native';

interface UseImageProps {
fileId: string;
imageSize?: 'small' | 'medium' | 'large' | 'full';
NaingAmity marked this conversation as resolved.
Show resolved Hide resolved
}

const useImage = ({ fileId, imageSize = 'medium' }: UseImageProps) => {
const [imageUrl, setImageUrl] = useState<string | undefined>(undefined);

useEffect(() => {
if (fileId == null) {
setImageUrl(undefined);
return;
}

async function run() {
const file = await FileRepository.getFile(fileId);
const newImageUrl = !file
? undefined
: await FileRepository.fileUrlWithSize(file.data.fileUrl, imageSize);
setImageUrl(newImageUrl);
}
run();
}, [fileId, imageSize]);

return imageUrl;
};

export default useImage;
Loading
Loading