Add profile, group, and Courses cards
This commit is contained in:
4
App.js
4
App.js
@@ -191,9 +191,9 @@ export default function App() {
|
|||||||
<NavigationContainer>
|
<NavigationContainer>
|
||||||
<Stack.Navigator>
|
<Stack.Navigator>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Home"
|
name="EMI Social"
|
||||||
component={MainNavigation}
|
component={MainNavigation}
|
||||||
options={{ headerShown: false }}
|
options={{ headerShown: true }}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="Profile"
|
name="Profile"
|
||||||
|
|||||||
103
Views/Courses.js
103
Views/Courses.js
@@ -1,23 +1,72 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Searchbar } from 'react-native-paper';
|
import { Searchbar } from 'react-native-paper';
|
||||||
import { View, ActivityIndicator, StyleSheet, SafeAreaView, FlatList } from 'react-native';
|
import { ScrollView, ActivityIndicator, StyleSheet, SafeAreaView, FlatList } from 'react-native';
|
||||||
|
import { Title } from 'react-native-paper';
|
||||||
import API from "../API";
|
import API from "../API";
|
||||||
import UserName from "../components/UserName";
|
import CourseCard from "../components/CourseCard";
|
||||||
import ProfileSmallHeader from '../components/ProfileSmallHeader.js'
|
|
||||||
|
|
||||||
|
const getCourses = async (profileObj) => {
|
||||||
|
let courses;
|
||||||
|
let popular;
|
||||||
|
await API.getCourses().then((data) => {
|
||||||
|
courses = data.groups;
|
||||||
|
popular = [...data.groups].sort((a, b) => {
|
||||||
|
return Object.keys(b.subscribed).length - Object.keys(a.subscribed).length;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let watching = {};
|
||||||
|
let watchingProms = [];
|
||||||
|
Object.keys(profileObj.data).forEach((videoId) => {
|
||||||
|
if (profileObj.data[videoId].profileId) {
|
||||||
|
let profileId = profileObj.data[videoId].profileId;
|
||||||
|
watchingProms.push(API.getUserProfile(profileId).then(profile => {
|
||||||
|
if (!profile.isCourse)
|
||||||
|
return 0;
|
||||||
|
if (!watching[profileId])
|
||||||
|
watching[profileId] = { profile, progress: [], mostRecent: 0 };
|
||||||
|
if (watching[profileId].mostRecent < profileObj.data[videoId].ts)
|
||||||
|
watching[profileId].mostRecent = profileObj.data[videoId].ts;
|
||||||
|
watching[profileId].progress.push(profileObj.data[videoId]);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let watchingArray = [];
|
||||||
|
await Promise.all(watchingProms).then(() => {
|
||||||
|
for (const courseId in watching) {
|
||||||
|
watchingArray.push(watching[courseId]);
|
||||||
|
}
|
||||||
|
watchingArray = watchingArray.sort((a, b) => {
|
||||||
|
return b.mostRecent - a.mostRecent;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
courses,
|
||||||
|
popular,
|
||||||
|
watching: watchingArray,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Courses = () => {
|
const Courses = () => {
|
||||||
|
const [Me, setMeProfile] = React.useState({});
|
||||||
const [searchQuery, setSearchQuery] = React.useState('');
|
const [searchQuery, setSearchQuery] = React.useState('');
|
||||||
const [groups, setGroups] = React.useState([]);
|
const [groups, setGroups] = React.useState([]);
|
||||||
|
const [popular, setPopular] = React.useState([]);
|
||||||
|
const [watching, setWatching] = React.useState([]);
|
||||||
const [queryTimer, setQueryTimer] = React.useState(0);
|
const [queryTimer, setQueryTimer] = React.useState(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(async () => {
|
||||||
API.getCourses('').then((data) => {
|
let Me = await API.getMe();
|
||||||
setGroups(data.groups || []);
|
setMeProfile(Me);
|
||||||
});
|
//API.getCourses('').then((data) => {
|
||||||
|
// setGroups(data.groups || []);
|
||||||
|
//});
|
||||||
|
let r = await getCourses(Me);
|
||||||
|
setGroups(r.courses || []);
|
||||||
|
setPopular(r.popular || []);
|
||||||
|
setWatching(r.watching || []);
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const onChangeSearch = query => {
|
const onChangeSearch = query => {
|
||||||
setSearchQuery(query);
|
setSearchQuery(query);
|
||||||
if (queryTimer) clearTimeout(queryTimer);
|
if (queryTimer) clearTimeout(queryTimer);
|
||||||
@@ -35,7 +84,10 @@ const Courses = () => {
|
|||||||
setQueryTimer(timerId);
|
setQueryTimer(timerId);
|
||||||
};
|
};
|
||||||
const renderProfile = (({ item }) => {
|
const renderProfile = (({ item }) => {
|
||||||
return (<ProfileSmallHeader profileObj={item} />);
|
return (<CourseCard profileObj={item} />);
|
||||||
|
});
|
||||||
|
const watchingCourse = (({ item }) => {
|
||||||
|
return (<CourseCard profileObj={item.profile} />);
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
@@ -44,11 +96,30 @@ const Courses = () => {
|
|||||||
onChangeText={onChangeSearch}
|
onChangeText={onChangeSearch}
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
/>
|
/>
|
||||||
<FlatList
|
{groups.length ? <></> : <ActivityIndicator />}
|
||||||
data={groups}
|
<ScrollView>
|
||||||
renderItem={renderProfile}
|
<Title>Continue Watching:</Title>
|
||||||
keyExtractor={item => item._id}
|
<FlatList
|
||||||
/>
|
horizontal={true}
|
||||||
|
data={watching}
|
||||||
|
renderItem={watchingCourse}
|
||||||
|
keyExtractor={item => item.profile._id}
|
||||||
|
/>
|
||||||
|
<Title>Recently Added:</Title>
|
||||||
|
<FlatList
|
||||||
|
horizontal={true}
|
||||||
|
data={groups}
|
||||||
|
renderItem={renderProfile}
|
||||||
|
keyExtractor={item => item._id}
|
||||||
|
/>
|
||||||
|
<Title>Popular:</Title>
|
||||||
|
<FlatList
|
||||||
|
horizontal={true}
|
||||||
|
data={popular}
|
||||||
|
renderItem={renderProfile}
|
||||||
|
keyExtractor={item => item._id}
|
||||||
|
/>
|
||||||
|
</ScrollView>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -57,7 +128,5 @@ export default Courses;
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
|
||||||
backgroundColor: "#edf2f7",
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Searchbar } from 'react-native-paper';
|
|||||||
import { View, ActivityIndicator, StyleSheet, SafeAreaView, FlatList } from 'react-native';
|
import { View, ActivityIndicator, StyleSheet, SafeAreaView, FlatList } from 'react-native';
|
||||||
import API from "../API";
|
import API from "../API";
|
||||||
import UserName from "../components/UserName";
|
import UserName from "../components/UserName";
|
||||||
|
import GroupCard from "../components/GroupCard";
|
||||||
import ProfileSmallHeader from '../components/ProfileSmallHeader.js'
|
import ProfileSmallHeader from '../components/ProfileSmallHeader.js'
|
||||||
|
|
||||||
const Groups = () => {
|
const Groups = () => {
|
||||||
@@ -35,16 +36,19 @@ const Groups = () => {
|
|||||||
setQueryTimer(timerId);
|
setQueryTimer(timerId);
|
||||||
};
|
};
|
||||||
const renderProfile = (({ item }) => {
|
const renderProfile = (({ item }) => {
|
||||||
return (<ProfileSmallHeader profileObj={item} />);
|
return (<GroupCard profileObj={item} />);
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView>
|
||||||
<Searchbar
|
<Searchbar
|
||||||
placeholder="Search Users"
|
placeholder="Search Groups"
|
||||||
onChangeText={onChangeSearch}
|
onChangeText={onChangeSearch}
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
/>
|
/>
|
||||||
<FlatList
|
<FlatList
|
||||||
|
contentContainerStyle={styles.container}
|
||||||
|
numColumns={2}
|
||||||
|
columnWrapperStyle={{justifyContent: "space-evenly"}}
|
||||||
data={groups}
|
data={groups}
|
||||||
renderItem={renderProfile}
|
renderItem={renderProfile}
|
||||||
keyExtractor={item => item._id}
|
keyExtractor={item => item._id}
|
||||||
@@ -57,7 +61,6 @@ export default Groups;
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
padding: 5,
|
||||||
backgroundColor: "#edf2f7",
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import React, {useEffect} from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Searchbar } from 'react-native-paper';
|
import { Searchbar } from 'react-native-paper';
|
||||||
import { View, ActivityIndicator, StyleSheet, SafeAreaView, FlatList } from 'react-native';
|
import { View, ScrollView, StyleSheet, SafeAreaView, FlatList } from 'react-native';
|
||||||
import API from "../API";
|
import API from "../API";
|
||||||
import UserName from "../components/UserName";
|
import UserName from "../components/UserName";
|
||||||
|
import ProfileCard from "../components/ProfileCard";
|
||||||
import ProfileSmallHeader from '../components/ProfileSmallHeader.js'
|
import ProfileSmallHeader from '../components/ProfileSmallHeader.js'
|
||||||
|
|
||||||
const Search = () => {
|
const Search = () => {
|
||||||
@@ -11,36 +12,40 @@ const Search = () => {
|
|||||||
const [queryTimer, setQueryTimer] = React.useState(0);
|
const [queryTimer, setQueryTimer] = React.useState(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
API.searchProfiles('').then((data)=>{
|
API.searchProfiles('').then((data) => {
|
||||||
setProfiles(data.profiles || []);
|
setProfiles(data.profiles || []);
|
||||||
});
|
});
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const onChangeSearch = query => {
|
const onChangeSearch = query => {
|
||||||
setSearchQuery(query);
|
setSearchQuery(query);
|
||||||
if(queryTimer) clearTimeout(queryTimer);
|
if (queryTimer) clearTimeout(queryTimer);
|
||||||
let timerId = setTimeout(()=>{
|
let timerId = setTimeout(() => {
|
||||||
API.searchProfiles(query).then((data)=>{
|
API.searchProfiles(query).then((data) => {
|
||||||
setProfiles(data.profiles || []);
|
setProfiles(data.profiles || []);
|
||||||
});
|
});
|
||||||
}, 300);
|
}, 300);
|
||||||
setQueryTimer(timerId);
|
setQueryTimer(timerId);
|
||||||
};
|
};
|
||||||
const renderProfile = (({ item }) => {
|
const renderProfile = (({ item }) => {
|
||||||
return (<ProfileSmallHeader profileObj={item} />);
|
return (<ProfileCard profileObj={item} />);
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView >
|
||||||
<Searchbar
|
<Searchbar
|
||||||
placeholder="Search Users"
|
placeholder="Search Users"
|
||||||
onChangeText={onChangeSearch}
|
onChangeText={onChangeSearch}
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
|
elevation={3}
|
||||||
/>
|
/>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={profiles}
|
contentContainerStyle={styles.container}
|
||||||
renderItem={renderProfile}
|
numColumns={2}
|
||||||
keyExtractor={item => item._id}
|
columnWrapperStyle={{justifyContent: "space-evenly"}}
|
||||||
/>
|
data={profiles}
|
||||||
|
renderItem={renderProfile}
|
||||||
|
keyExtractor={item => item._id}
|
||||||
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -49,7 +54,6 @@ export default Search;
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
padding: 5,
|
||||||
backgroundColor: "#edf2f7",
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
104
components/CourseCard.js
Normal file
104
components/CourseCard.js
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Text, StyleSheet, View } from 'react-native';
|
||||||
|
import Icon from 'react-native-vector-icons/MaterialIcons';
|
||||||
|
import { Avatar, Card, Title, Paragraph } from 'react-native-paper';
|
||||||
|
import API from './../API.js';
|
||||||
|
import { useNavigation } from '@react-navigation/native';
|
||||||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
|
||||||
|
const DefaultPhoto = "https://social.emmint.com/uploads/e6f9be6d665dc43417701bf16a90122c.png";
|
||||||
|
|
||||||
|
const storeName = async (key, value) => {
|
||||||
|
try {
|
||||||
|
const jsonValue = JSON.stringify(value)
|
||||||
|
await AsyncStorage.setItem('Name_' + key, jsonValue)
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getName = async (key) => {
|
||||||
|
try {
|
||||||
|
const value = await AsyncStorage.getItem('Name_' + key)
|
||||||
|
if (value !== null) {
|
||||||
|
return JSON.parse(value);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let CourseCard = ({ profileid, hideIcon, profileObj }) => {
|
||||||
|
let [profile, setProfile] = useState(profileObj || {});
|
||||||
|
const navigation = useNavigation();
|
||||||
|
|
||||||
|
useEffect(async () => {
|
||||||
|
if (profileObj._id) return 0;
|
||||||
|
let cacheProfile = await getName(profileid);
|
||||||
|
if (cacheProfile && cacheProfile.profile) setProfile(cacheProfile);
|
||||||
|
let p = await API.getUserProfile(profileid).catch(() => { return {} });
|
||||||
|
setProfile(p);
|
||||||
|
storeName(profileid, p)
|
||||||
|
}, [profileid]);
|
||||||
|
|
||||||
|
let icon = profile._id ? (!profile.isGroup ? "person-outline" : "group") : '';
|
||||||
|
icon = icon === "person-outline" && profile.subscription && profile.subscription > (new Date() - 0) ? "assignment-ind" : icon;
|
||||||
|
icon = icon === "group" && profile.isCourse ? "subscriptions" : icon;
|
||||||
|
let photoUrl = profile.data && profile.data.profileImg ? profile.data.profileImg : DefaultPhoto;
|
||||||
|
|
||||||
|
const onPress = () => {
|
||||||
|
return navigation.navigate('Profile', { profileid: profile._id })
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card style={styles.content}>
|
||||||
|
<Card.Content>
|
||||||
|
<Title onPress={onPress} numberOfLines={2}>
|
||||||
|
<Text style={{ paddingTop: 10 }}>
|
||||||
|
{!hideIcon ? <Icon name={icon} size={18} /> : <></>}
|
||||||
|
</Text>
|
||||||
|
<Text>
|
||||||
|
{profile.profile && profile.profile.firstName} {profile.profile && profile.profile.lastName}
|
||||||
|
</Text>
|
||||||
|
</Title>
|
||||||
|
<Paragraph numberOfLines={2}>
|
||||||
|
{profileObj.profile.description ? profileObj.profile.description : "We are working on this course description, soon to come!"}
|
||||||
|
</Paragraph>
|
||||||
|
{profile.data ?
|
||||||
|
<View style={{flexDirection: "row", marginTop:5}}>
|
||||||
|
<Avatar.Image size={64} source={{ uri: photoUrl }} />
|
||||||
|
<View>
|
||||||
|
<Text>By: {profile.data.author ? profile.data.author : 'Working on this'}</Text>
|
||||||
|
<Text>
|
||||||
|
<Icon name="date-range" />
|
||||||
|
{profile.data.year ? profile.data.year : 'XXXX'}
|
||||||
|
</Text>
|
||||||
|
<Text>
|
||||||
|
<Icon name="timer" />
|
||||||
|
{profile.data.duration ? profile.data.duration : '??'}
|
||||||
|
</Text>
|
||||||
|
<Text>
|
||||||
|
<Icon name="language" />
|
||||||
|
{profile.data.language}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
: <></>
|
||||||
|
}
|
||||||
|
</Card.Content>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(CourseCard);
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
content: {
|
||||||
|
margin: 4,
|
||||||
|
width: 250,
|
||||||
|
},
|
||||||
|
centerItems: {
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
}
|
||||||
|
});
|
||||||
86
components/GroupCard.js
Normal file
86
components/GroupCard.js
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Text, StyleSheet } from 'react-native';
|
||||||
|
import Icon from 'react-native-vector-icons/MaterialIcons';
|
||||||
|
import { Avatar, Button, Card, Title, Paragraph } from 'react-native-paper';
|
||||||
|
import API from './../API.js';
|
||||||
|
import { useNavigation } from '@react-navigation/native';
|
||||||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
|
||||||
|
const DefaultPhoto = "https://social.emmint.com/uploads/e6f9be6d665dc43417701bf16a90122c.png";
|
||||||
|
|
||||||
|
const storeName = async (key, value) => {
|
||||||
|
try {
|
||||||
|
const jsonValue = JSON.stringify(value)
|
||||||
|
await AsyncStorage.setItem('Name_' + key, jsonValue)
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getName = async (key) => {
|
||||||
|
try {
|
||||||
|
const value = await AsyncStorage.getItem('Name_' + key)
|
||||||
|
if (value !== null) {
|
||||||
|
return JSON.parse(value);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ProfileCard = ({ profileid, hideIcon, profileObj }) => {
|
||||||
|
let [profile, setProfile] = useState(profileObj || {});
|
||||||
|
const navigation = useNavigation();
|
||||||
|
|
||||||
|
useEffect(async () => {
|
||||||
|
if (profileObj._id) return 0;
|
||||||
|
let cacheProfile = await getName(profileid);
|
||||||
|
if (cacheProfile && cacheProfile.profile) setProfile(cacheProfile);
|
||||||
|
let p = await API.getUserProfile(profileid).catch(() => { return {} });
|
||||||
|
setProfile(p);
|
||||||
|
storeName(profileid, p)
|
||||||
|
}, [profileid]);
|
||||||
|
|
||||||
|
let icon = profile._id ? (!profile.isGroup ? "person-outline" : "group") : '';
|
||||||
|
icon = icon === "person-outline" && profile.subscription && profile.subscription > (new Date() - 0) ? "assignment-ind" : icon;
|
||||||
|
icon = icon === "group" && profile.isCourse ? "subscriptions" : icon;
|
||||||
|
let photoUrl = profile.profile.photo ? 'https://social.emmint.com/' + profile.profile.photo : DefaultPhoto;
|
||||||
|
|
||||||
|
const onPress = () => {
|
||||||
|
return navigation.navigate('Profile', { profileid: profile._id })
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card style={styles.content}>
|
||||||
|
<Card.Content>
|
||||||
|
<Title onPress={onPress} numberOfLines={1}>
|
||||||
|
<Text style={{ paddingTop: 10 }}>
|
||||||
|
{!hideIcon ? <Icon name={icon} size={18} /> : <></>}
|
||||||
|
</Text>
|
||||||
|
<Text>
|
||||||
|
{profile.profile && profile.profile.firstName} {profile.profile && profile.profile.lastName}
|
||||||
|
</Text>
|
||||||
|
</Title>
|
||||||
|
<Paragraph numberOfLines={4}>{profileObj.profile.description}</Paragraph>
|
||||||
|
<Text>
|
||||||
|
<Button mode='outlined'>Follow</Button>
|
||||||
|
<Text><Icon name={"hail"} size={18} />
|
||||||
|
{Object.keys(profile.subscribed).length}</Text>
|
||||||
|
</Text>
|
||||||
|
</Card.Content>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(ProfileCard);
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
content: {
|
||||||
|
margin: 4,
|
||||||
|
width: "50%",
|
||||||
|
},
|
||||||
|
centerItems: {
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -3,6 +3,7 @@ import { Text, View, ScrollView, Image, StyleSheet } from 'react-native';
|
|||||||
import API from './../API.js';
|
import API from './../API.js';
|
||||||
import VideoPlayer from './VideoPlayer.js';
|
import VideoPlayer from './VideoPlayer.js';
|
||||||
import VimeoPlayer from './VimeoPlayer.js';
|
import VimeoPlayer from './VimeoPlayer.js';
|
||||||
|
import { WebView } from 'react-native-webview';
|
||||||
|
|
||||||
const videoIdF = (content) => {
|
const videoIdF = (content) => {
|
||||||
let vimeoTag = content.match(/@vimeo:[0-9]+/);
|
let vimeoTag = content.match(/@vimeo:[0-9]+/);
|
||||||
@@ -28,7 +29,7 @@ const imagesTagF = (content) => {
|
|||||||
|
|
||||||
const iframeTagF = (content) => {
|
const iframeTagF = (content) => {
|
||||||
let iframeMatch = content.match(/@iframe:.+\w/g);
|
let iframeMatch = content.match(/@iframe:.+\w/g);
|
||||||
if (!iframeMatch) return 0;
|
if (!iframeMatch) return [];
|
||||||
let tag = iframeMatch[0].substring(1);
|
let tag = iframeMatch[0].substring(1);
|
||||||
let parts = [tag.substring(1, tag.indexOf(":")), tag.substring(tag.indexOf(":") + 1)];
|
let parts = [tag.substring(1, tag.indexOf(":")), tag.substring(tag.indexOf(":") + 1)];
|
||||||
return parts;
|
return parts;
|
||||||
@@ -39,14 +40,20 @@ let Media = (props) => {
|
|||||||
const imagesTag = imagesTagF(props.content);
|
const imagesTag = imagesTagF(props.content);
|
||||||
const imageStyle = imagesTag.length == 1 ? styles.image : styles.multipleImage;
|
const imageStyle = imagesTag.length == 1 ? styles.image : styles.multipleImage;
|
||||||
const videosId = videoIdF(props.content);
|
const videosId = videoIdF(props.content);
|
||||||
|
const iframeSrc = iframeTagF(props.content) || [];
|
||||||
let [videosFiles, setVideosFiles] = useState([]);
|
let [videosFiles, setVideosFiles] = useState([]);
|
||||||
useEffect(async () => {
|
useEffect(async () => {
|
||||||
if (!videosId[1]) return 0;
|
if (!videosId[1]) return 0;
|
||||||
let videoObj = await API.getVideo(videosId[1]);
|
let videoObj = await API.getVideo(videosId[1]);
|
||||||
setVideosFiles(videoObj.files || []);
|
setVideosFiles(videoObj.files || []);
|
||||||
}, [props.content])
|
}, [props.content])
|
||||||
const vimeo = videosFiles.length ? <VideoPlayer videosFiles={videosFiles} /> :
|
const video = videosFiles.length ? <VideoPlayer videosFiles={videosFiles} /> :
|
||||||
(videosId.length ? <VimeoPlayer videoId={videosId[1]} /> : <></>);
|
(videosId.length ? <VimeoPlayer videoId={videosId[1]} /> : <></>);
|
||||||
|
const iframe = iframeSrc.length ?
|
||||||
|
<WebView
|
||||||
|
style={styles.iframe}
|
||||||
|
source={{ uri: iframeSrc[1] }}
|
||||||
|
/> : <></>;
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<View style={{ flexDirection: "row" }}>
|
<View style={{ flexDirection: "row" }}>
|
||||||
@@ -59,7 +66,8 @@ let Media = (props) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
</View>
|
</View>
|
||||||
{vimeo}
|
{video}
|
||||||
|
{iframe}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -75,5 +83,9 @@ const styles = StyleSheet.create({
|
|||||||
width: "49%",
|
width: "49%",
|
||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
||||||
margin: 2,
|
margin: 2,
|
||||||
|
},
|
||||||
|
iframe:{
|
||||||
|
width: "100%",
|
||||||
|
minHeight: 300,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
80
components/ProfileCard.js
Normal file
80
components/ProfileCard.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Text, StyleSheet } from 'react-native';
|
||||||
|
import Icon from 'react-native-vector-icons/MaterialIcons';
|
||||||
|
import { Avatar, Button, Card, Title, Paragraph } from 'react-native-paper';
|
||||||
|
import API from './../API.js';
|
||||||
|
import { useNavigation } from '@react-navigation/native';
|
||||||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
|
||||||
|
const DefaultPhoto = "https://social.emmint.com/uploads/e6f9be6d665dc43417701bf16a90122c.png";
|
||||||
|
|
||||||
|
const storeName = async (key, value) => {
|
||||||
|
try {
|
||||||
|
const jsonValue = JSON.stringify(value)
|
||||||
|
await AsyncStorage.setItem('Name_' + key, jsonValue)
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getName = async (key) => {
|
||||||
|
try {
|
||||||
|
const value = await AsyncStorage.getItem('Name_' + key)
|
||||||
|
if (value !== null) {
|
||||||
|
return JSON.parse(value);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ProfileCard = ({ profileid, hideIcon, profileObj }) => {
|
||||||
|
let [profile, setProfile] = useState(profileObj || {});
|
||||||
|
const navigation = useNavigation();
|
||||||
|
|
||||||
|
useEffect(async () => {
|
||||||
|
if (profileObj._id) return 0;
|
||||||
|
let cacheProfile = await getName(profileid);
|
||||||
|
if (cacheProfile && cacheProfile.profile) setProfile(cacheProfile);
|
||||||
|
let p = await API.getUserProfile(profileid).catch(() => { return {} });
|
||||||
|
setProfile(p);
|
||||||
|
storeName(profileid, p)
|
||||||
|
}, [profileid]);
|
||||||
|
|
||||||
|
let icon = profile._id ? (!profile.isGroup ? "person-outline" : "group") : '';
|
||||||
|
icon = icon === "person-outline" && profile.subscription && profile.subscription > (new Date() - 0) ? "assignment-ind" : icon;
|
||||||
|
icon = icon === "group" && profile.isCourse ? "subscriptions" : icon;
|
||||||
|
let photoUrl = profile.profile.photo ? 'https://social.emmint.com/' + profile.profile.photo : DefaultPhoto;
|
||||||
|
|
||||||
|
const onPress = () => {
|
||||||
|
return navigation.navigate('Profile', { profileid: profile._id })
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card style={styles.content}>
|
||||||
|
<Card.Content>
|
||||||
|
<Avatar.Image size={150} source={{ uri: photoUrl }} />
|
||||||
|
<Title onPress={onPress} numberOfLines={1}>
|
||||||
|
<Text>
|
||||||
|
{profile.profile && profile.profile.firstName} {profile.profile && profile.profile.lastName}
|
||||||
|
</Text>
|
||||||
|
</Title>
|
||||||
|
<Paragraph numberOfLines={2}>{profileObj.profile.description}</Paragraph>
|
||||||
|
<Button mode='outlined'>Follow</Button>
|
||||||
|
</Card.Content>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(ProfileCard);
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
content: {
|
||||||
|
margin: 4,
|
||||||
|
width: "50%",
|
||||||
|
},
|
||||||
|
centerItems:{
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -6,7 +6,7 @@ import UserName from './UserName';
|
|||||||
const DefaultPhoto = "https://social.emmint.com/uploads/e6f9be6d665dc43417701bf16a90122c.png";
|
const DefaultPhoto = "https://social.emmint.com/uploads/e6f9be6d665dc43417701bf16a90122c.png";
|
||||||
|
|
||||||
const ProfileHeader = ({ profileObj }) => {
|
const ProfileHeader = ({ profileObj }) => {
|
||||||
let photoUrl = profileObj.profile.photo ? 'https://social.emmint.com/' + profileObj.profile.photo : DefaultPhoto;
|
let photoUrl = profileObj.profile && profileObj.profile.photo ? 'https://social.emmint.com/' + profileObj.profile.photo : DefaultPhoto;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card elevation={3}>
|
<Card elevation={3}>
|
||||||
|
|||||||
Reference in New Issue
Block a user