Feed showing posts
This commit is contained in:
7
App.js
7
App.js
@@ -1,6 +1,6 @@
|
|||||||
import { StatusBar } from 'expo-status-bar';
|
import { StatusBar } from 'expo-status-bar';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { StyleSheet, Text, View, TextInput } from 'react-native';
|
import { StyleSheet, Text, View, TextInput, SafeAreaView } from 'react-native';
|
||||||
import API from './API.js';
|
import API from './API.js';
|
||||||
import LoginForm from './components/Login.js';
|
import LoginForm from './components/Login.js';
|
||||||
import Feed from './components/Feed.js';
|
import Feed from './components/Feed.js';
|
||||||
@@ -14,12 +14,12 @@ export default function App() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<Text>EMI Social LOGO</Text>
|
<Text>EMI Social LOGO</Text>
|
||||||
{!isLoggedIn && <LoginForm />}
|
{!isLoggedIn && <LoginForm />}
|
||||||
{isLoggedIn && <Feed />}
|
{isLoggedIn && <Feed />}
|
||||||
<StatusBar style="auto" />
|
<StatusBar style="auto" />
|
||||||
</View>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,5 +29,6 @@ const styles = StyleSheet.create({
|
|||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
marginTop: 30,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { StatusBar } from 'expo-status-bar';
|
import { StatusBar } from 'expo-status-bar';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Text, View, ScrollView, Button } from 'react-native';
|
import { Text, View, ScrollView, Button, StyleSheet } from 'react-native';
|
||||||
import API from './../API.js';
|
import API from './../API.js';
|
||||||
|
import Post from './Post.js'
|
||||||
|
|
||||||
|
|
||||||
let Feed = () => {
|
let Feed = () => {
|
||||||
@@ -11,18 +12,18 @@ let Feed = () => {
|
|||||||
let r = await API.getMe();
|
let r = await API.getMe();
|
||||||
setMeProfile(r);
|
setMeProfile(r);
|
||||||
let posts = await API.getPosts();
|
let posts = await API.getPosts();
|
||||||
setPosts(posts)
|
setPosts(posts);
|
||||||
//console.log(posts)
|
//console.log(posts)
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
<Text>Hello: {Me.profile && Me.profile.firstName} {Me.profile && Me.profile.lastName}</Text>
|
|
||||||
{
|
{
|
||||||
Posts.map((post, i) => {
|
Posts.map((post, i) => {
|
||||||
return (
|
return (
|
||||||
<Text key={i}>{post.content}</Text>
|
//<Text key={i}>{post.content}</Text>
|
||||||
|
<Post post={post} key={i}/>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { StatusBar } from 'expo-status-bar';
|
import { StatusBar } from 'expo-status-bar';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Text, View, TextInput, Button } from 'react-native';
|
import { Text, View, TextInput, Button, StyleSheet } from 'react-native';
|
||||||
import API from './../API.js';
|
import API from './../API.js';
|
||||||
|
|
||||||
|
|
||||||
@@ -9,31 +9,27 @@ let LoginForm = ()=>{
|
|||||||
let [password, setPassword] = useState('');
|
let [password, setPassword] = useState('');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<View style={styles.mainView}>
|
||||||
<Text>Log in</Text>
|
<Text>Log in</Text>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={{
|
style={styles.input}
|
||||||
height: 40,
|
|
||||||
width: 200,
|
|
||||||
borderColor: 'gray',
|
|
||||||
borderWidth: 1
|
|
||||||
}}
|
|
||||||
onChangeText={text => setEmail(text)}
|
onChangeText={text => setEmail(text)}
|
||||||
defaultValue={email}
|
defaultValue={email}
|
||||||
placeholder=" email"
|
placeholder=" email"
|
||||||
|
autoCapitalize='none'
|
||||||
|
autoComplete='email'
|
||||||
|
autoCorrect={false}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={{
|
style={styles.input}
|
||||||
height: 40,
|
|
||||||
width: 200,
|
|
||||||
borderColor: 'gray',
|
|
||||||
borderWidth: 1
|
|
||||||
}}
|
|
||||||
onChangeText={text => setPassword(text)}
|
onChangeText={text => setPassword(text)}
|
||||||
defaultValue={password}
|
defaultValue={password}
|
||||||
placeholder=" password"
|
placeholder=" password"
|
||||||
textContentType="password"
|
textContentType="password"
|
||||||
secureTextEntry={true}
|
secureTextEntry={true}
|
||||||
|
autoCapitalize='none'
|
||||||
|
autoComplete='email'
|
||||||
|
autoCorrect={false}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
@@ -47,3 +43,20 @@ let LoginForm = ()=>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default LoginForm;
|
export default LoginForm;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create ({
|
||||||
|
mainView:{
|
||||||
|
flex: 1,
|
||||||
|
flexDirection:'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
backgroundColor: 'rgba(255, 0, 255, 1.0)',
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
height: 40,
|
||||||
|
width: 300,
|
||||||
|
borderColor: 'gray',
|
||||||
|
borderWidth: 1,
|
||||||
|
margin: 10
|
||||||
|
},
|
||||||
|
});
|
||||||
73
components/Media.js
Normal file
73
components/Media.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Text, View, ScrollView, Image, StyleSheet } from 'react-native';
|
||||||
|
import API from './../API.js';
|
||||||
|
import VimeoPlayer from './VimeoPlayer.js'
|
||||||
|
|
||||||
|
const videoIdF = (content) => {
|
||||||
|
let vimeoTag = content.match(/@vimeo:[0-9]+/);
|
||||||
|
let youtubeTag = content.match(/@youtube:[0-z]+/);
|
||||||
|
if (!vimeoTag && !youtubeTag) return [];
|
||||||
|
let tag = youtubeTag || vimeoTag;
|
||||||
|
tag = tag[0].substring(1);
|
||||||
|
return tag.split(':');
|
||||||
|
};
|
||||||
|
|
||||||
|
const imagesTagF = (content) => {
|
||||||
|
let images = content.match(/@image:[0-z|/|.|]+/g);
|
||||||
|
if (!images) return [];
|
||||||
|
let Tags = [];
|
||||||
|
images.forEach(i => {
|
||||||
|
let tag = i.substring(1);
|
||||||
|
let parts = [tag.substring(1, tag.indexOf(":")), tag.substring(tag.indexOf(":") + 1)];
|
||||||
|
if (parts[1].substring(0, 4) != "http") parts[1] = "https://social.emmint.com/" + parts[1];
|
||||||
|
Tags.push(parts);
|
||||||
|
});
|
||||||
|
return Tags;
|
||||||
|
};
|
||||||
|
|
||||||
|
const iframeTagF = (content) => {
|
||||||
|
let iframeMatch = content.match(/@iframe:.+\w/g);
|
||||||
|
if (!iframeMatch) return 0;
|
||||||
|
let tag = iframeMatch[0].substring(1);
|
||||||
|
let parts = [tag.substring(1, tag.indexOf(":")), tag.substring(tag.indexOf(":") + 1)];
|
||||||
|
return parts;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let Media = (props) => {
|
||||||
|
const imagesTag = imagesTagF(props.content);
|
||||||
|
const imageStyle = imagesTag.length == 1 ? styles.image : styles.multipleImage;
|
||||||
|
const videosId = videoIdF(props.content);
|
||||||
|
console.log(videosId);
|
||||||
|
const vimeo = videosId.length ? <VimeoPlayer videoId={videosId[1]} /> : undefined;
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<View style={{flexDirection: "row"}}>
|
||||||
|
{
|
||||||
|
imagesTag.map((image, i) => {
|
||||||
|
return (
|
||||||
|
//<Text key={i}>{post.content}</Text>
|
||||||
|
<Image source={{uri: image[1]}} key={image[1]} style={imageStyle} />
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</View>
|
||||||
|
{vimeo}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Media;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
image:{
|
||||||
|
width: "100%",
|
||||||
|
aspectRatio: 1,
|
||||||
|
},
|
||||||
|
multipleImage:{
|
||||||
|
width: "49%",
|
||||||
|
aspectRatio: 1,
|
||||||
|
margin: 2,
|
||||||
|
}
|
||||||
|
});
|
||||||
46
components/Post.js
Normal file
46
components/Post.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Text, View, ScrollView, Button, StyleSheet } from 'react-native';
|
||||||
|
import API from './../API.js';
|
||||||
|
import UserName from './UserName.js';
|
||||||
|
import Media from './Media.js';
|
||||||
|
|
||||||
|
|
||||||
|
let Post = (props) => {
|
||||||
|
|
||||||
|
let toProfileText = props.post.toProfile && props.post.toProfile !== props.post.profileid ?
|
||||||
|
<Text> {">"} <UserName profileid={props.post.toProfile} /></Text> : undefined;
|
||||||
|
|
||||||
|
let cleanContent = props.post.content.replace(/@[A-z]+:.+\w/g, '');
|
||||||
|
return (
|
||||||
|
<View style={styles.postView}>
|
||||||
|
<Text style={styles.userName}>
|
||||||
|
<UserName profileid={props.post.profileid} />
|
||||||
|
{toProfileText}
|
||||||
|
</Text>
|
||||||
|
<Text>{cleanContent}</Text>
|
||||||
|
<Media content={props.post.content} />
|
||||||
|
<View style={{flexDirection: "row", flow: 4, justifyContent: 'space-between'}}>
|
||||||
|
<Button title='Like' style={{flow:1}} />
|
||||||
|
<Button title='Comment' style={{flow:1}} />
|
||||||
|
<Button title='Share' style={{flow:1}} />
|
||||||
|
<Button title='Book' style={{flow:1}} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Post;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
userName: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: 5,
|
||||||
|
},
|
||||||
|
postView: {
|
||||||
|
margin: 8,
|
||||||
|
borderColor: 'gray',
|
||||||
|
borderWidth: 1,
|
||||||
|
padding: 10
|
||||||
|
}
|
||||||
|
});
|
||||||
22
components/UserName.js
Normal file
22
components/UserName.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Text, View, ScrollView, Button, StyleSheet } from 'react-native';
|
||||||
|
import API from './../API.js';
|
||||||
|
|
||||||
|
|
||||||
|
let UserName = (props) => {
|
||||||
|
let [profile, setProfile] = useState({});
|
||||||
|
|
||||||
|
useEffect(async () => {
|
||||||
|
let p = await API.getUserProfile(props.profileid).catch(()=>{return {}});
|
||||||
|
setProfile(p);
|
||||||
|
}, [props.profileid]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Text>{profile.profile && profile.profile.firstName} {profile.profile && profile.profile.lastName}</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserName;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
});
|
||||||
37
components/VimeoPlayer.js
Normal file
37
components/VimeoPlayer.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { string, func } from 'prop-types';
|
||||||
|
import WebView from 'react-native-autoheight-webview';
|
||||||
|
|
||||||
|
const VimeoPlayer = ({ videoId, onError }) => {
|
||||||
|
return (
|
||||||
|
<WebView
|
||||||
|
style={style}
|
||||||
|
onError={onError}
|
||||||
|
allowsFullscreenVideo
|
||||||
|
scrollEnabled={false}
|
||||||
|
automaticallyAdjustContentInsets
|
||||||
|
source={{
|
||||||
|
html: `
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<iframe src="https://player.vimeo.com/video/${videoId}" width="100%" height="200px" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||||
|
<script src="https://player.vimeo.com/api/player.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VimeoPlayer;
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
height: 200,
|
||||||
|
maxWidth: '100%',
|
||||||
|
};
|
||||||
|
|
||||||
|
VimeoPlayer.propTypes = {
|
||||||
|
videoId: string,
|
||||||
|
onError: func,
|
||||||
|
};
|
||||||
9779
package-lock.json
generated
9779
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -14,8 +14,11 @@
|
|||||||
"expo-status-bar": "~1.1.0",
|
"expo-status-bar": "~1.1.0",
|
||||||
"react": "17.0.1",
|
"react": "17.0.1",
|
||||||
"react-dom": "17.0.1",
|
"react-dom": "17.0.1",
|
||||||
|
"react-google-material-icons": "^1.0.4",
|
||||||
"react-native": "0.64.3",
|
"react-native": "0.64.3",
|
||||||
"react-native-web": "0.17.1"
|
"react-native-autoheight-webview": "^1.6.1",
|
||||||
|
"react-native-web": "0.17.1",
|
||||||
|
"react-native-webview": "^11.17.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.12.9"
|
"@babel/core": "^7.12.9"
|
||||||
|
|||||||
Reference in New Issue
Block a user