diff --git a/public/images/69.jpg b/public/images/69.jpg deleted file mode 100644 index a573f2a..0000000 Binary files a/public/images/69.jpg and /dev/null differ diff --git a/public/profile.json b/public/profile.json index 3984235..eac46db 100644 --- a/public/profile.json +++ b/public/profile.json @@ -4,8 +4,12 @@ "avatar":"", "follows":[ { - "url":"", + "url":"dat://6ce0b49e9b045877a18669a1f287a101fb99d8881d2f9fa4ce0486c022c2397d/", "name":"~~|| dead staff ||~~" + }, + { + "url":"dat://7fcca9b6889e23b39a59de3780a74445e49ab722b1cd23358381760d6202a606/", + "name":"another dead staff" } ] } \ No newline at end of file diff --git a/src/components/ContentSelection/ImagePost/ImageForm.js b/src/components/ContentSelection/ImagePost/ImageForm.js index 28b2fa1..92577ef 100644 --- a/src/components/ContentSelection/ImagePost/ImageForm.js +++ b/src/components/ContentSelection/ImagePost/ImageForm.js @@ -12,7 +12,6 @@ const ImageForm = ({ resetImagePath }) => (
submitFn(e)} encType="multipart/form-data"> - {console.log('imageFile', imageFile)}
( -
-

Settings

-

Settings will go here!

-
-); - -export default ContentViewLoop; diff --git a/src/components/ContentView/index.js b/src/components/ContentView/index.js index ab30147..cb03eae 100644 --- a/src/components/ContentView/index.js +++ b/src/components/ContentView/index.js @@ -1,7 +1,6 @@ import React from 'react'; import ContentViewLoop from './ContentViewLoop'; -import Settings from './Settings'; const ContentView = ({ posts, @@ -27,7 +26,6 @@ const ContentView = ({ isOwner={isOwner} /> )} - {postDisplay === 'settings' && } ); diff --git a/src/components/Following/FollowSuggestions.js b/src/components/Following/FollowSuggestions.js new file mode 100644 index 0000000..3d842e3 --- /dev/null +++ b/src/components/Following/FollowSuggestions.js @@ -0,0 +1,5 @@ +import React from 'react'; + +const FollowSuggestions = () =>
Who to follow
; + +export default FollowSuggestions; diff --git a/src/components/Following/Follows.js b/src/components/Following/Follows.js new file mode 100644 index 0000000..bf90935 --- /dev/null +++ b/src/components/Following/Follows.js @@ -0,0 +1,13 @@ +import React from 'react'; + +const Follows = ({ follows }) => ( +
+ {follows && + follows.map((follow, i) => ( +
+ {follow.name} +
+ ))} +
+); +export default Follows; diff --git a/src/components/Following/NewFollow.js b/src/components/Following/NewFollow.js new file mode 100644 index 0000000..091ba65 --- /dev/null +++ b/src/components/Following/NewFollow.js @@ -0,0 +1,13 @@ +import React from 'react'; + +const NewFollow = ({ addFollower }) => ( +
+

Add User

+ addFollower(e)}> + + + +
+); + +export default NewFollow; diff --git a/src/components/Header/index.js b/src/components/Header/index.js index b97de4c..fe9798a 100644 --- a/src/components/Header/index.js +++ b/src/components/Header/index.js @@ -49,14 +49,14 @@ const Header = ({ togglePostDisplay('settings')} + ${'ContentDisplayToggle__Item'} + ${ + postDisplay === 'settings' + ? 'ContentDisplayToggle__Item_Selected' + : '' + } + `} + href="/settings" > diff --git a/src/components/SharedComponents/Profile/ProfileEdit.js b/src/components/SharedComponents/Profile/ProfileEdit.js new file mode 100644 index 0000000..9e55799 --- /dev/null +++ b/src/components/SharedComponents/Profile/ProfileEdit.js @@ -0,0 +1,58 @@ +import React from 'react'; + +const ProfileEdit = ({ + userAvatar, + userName, + userBio, + changeFn, + updateUserData +}) => ( +
+
updateUserData(e)}> +
+ changeFn(e, 'avatar')} + /> + +
+
+ changeFn(e, 'name')} + /> + +
+
+ changeFn(e, 'bio')} + /> + +
+ +
+
+); + +export default ProfileEdit; diff --git a/src/components/SharedComponents/Profile/index.js b/src/components/SharedComponents/Profile/index.js new file mode 100644 index 0000000..c09bf39 --- /dev/null +++ b/src/components/SharedComponents/Profile/index.js @@ -0,0 +1,41 @@ +import React from 'react'; + +import ProfileEdit from './ProfileEdit'; + +const Profile = ({ + userAvatar, + userName, + userBio, + editProfile, + changeFn, + updateUserData +}) => ( +
+ {editProfile ? ( + + ) : ( +
+
+

Avatar

+ {userAvatar} +
+
+

Name

+

{userName}

+
+
+

Bio

+

{userBio}

+
+
+ )} +
+); + +export default Profile; diff --git a/src/config.js b/src/config.js index ff9f3e4..dd2f617 100644 --- a/src/config.js +++ b/src/config.js @@ -1,2 +1,7 @@ +//--- Nick +// export const DAT_URL = +// 'aeac0a57a7f65ea03693909d817e93d8340c243137ed483076d7b68b18d09c61'; + +//--- James export const DAT_URL = - 'aeac0a57a7f65ea03693909d817e93d8340c243137ed483076d7b68b18d09c61'; + '7fcca9b6889e23b39a59de3780a74445e49ab722b1cd23358381760d6202a606'; diff --git a/src/containers/App/App.js b/src/containers/App/App.js index 8742b82..ebdb9a1 100644 --- a/src/containers/App/App.js +++ b/src/containers/App/App.js @@ -1,9 +1,12 @@ import React, { Component } from 'react'; import { BrowserRouter as Router, Route } from 'react-router-dom'; import sortBy from 'lodash.sortby'; +import urlEnv from '../../utils/urlEnv'; +import profileContents from '../../utils/profileContents'; +import { queryFollowers, followURLCheck } from '../../utils/following'; import ContentViewContainer from '../ContentViewContainer'; -import urlEnv from '../../utils/urlEnv'; +import Settings from '../Settings'; import PostContainer from '../PostContainer/index'; class App extends Component { @@ -15,7 +18,10 @@ class App extends Component { correctBrowser: true, isOwner: false, posts: [], - postDisplay: 'theirs' + theirPosts: [], + postDisplay: 'mine', + editProfile: false, + userData: {} }; } @@ -23,12 +29,14 @@ class App extends Component { try { const archive = await new global.DatArchive(urlEnv()); const archiveInfo = await archive.getInfo(); - const allPosts = await this.getAllPosts(archive); + const results = await this.refreshPosts(archive); + const theirresults = await this.refreshTheirPosts(archive); const userData = await this.getUserInfo(archive); this.setState({ correctBrowser: true, - posts: allPosts, + posts: results, + theirPosts: theirresults, loading: false, ...(archiveInfo.isOwner && { isOwner: true }), deadTitle: archiveInfo.title, @@ -36,7 +44,7 @@ class App extends Component { userData }); } catch (error) { - console.log(error); + console.log('try error', error); this.setState({ loading: false, correctBrowser: false @@ -57,20 +65,16 @@ class App extends Component { }); }; - /* - * This method takes an archive and - * returns all of their posts. - * It does not setState. - */ - getAllPosts = async archive => { - const posts = await archive.readdir('/posts'); + refreshTheirPosts = async archive => { + await queryFollowers(); + const posts = await archive.readdir('/theirposts'); if (posts.length === 0) { this.setState({ - posts: [] + theirPosts: [] }); } else { const promises = posts.map(async post => { - const postResponse = await archive.readFile(`/posts/${post}`); + const postResponse = await archive.readFile(`/theirposts/${post}`); return JSON.parse(postResponse); }); const results = await Promise.all(promises); @@ -78,11 +82,7 @@ class App extends Component { } }; - /* - * Exact same as the above function, but - * also sets state. - */ - getAllPostsSaved = async archive => { + refreshPosts = async archive => { const posts = await archive.readdir('/posts'); if (posts.length === 0) { this.setState({ @@ -94,9 +94,7 @@ class App extends Component { return JSON.parse(postResponse); }); const results = await Promise.all(promises); - this.setState({ - posts: results - }); + return results; } }; @@ -130,9 +128,67 @@ class App extends Component { window.location.href = '/'; }; + addFollower = e => { + e.preventDefault(); + // 1. input dat URL into input field + const followerFieldVal = document.querySelector('#add-follower-input') + .value; + // 2. regex in dat:// + + /*--- + 3. query for dat URL + 3a. return true or false message if valid dat URL + ---*/ + const followerData = { + name: '', + url: followURLCheck(followerFieldVal) + }; + if (followerData.url === '') { + return null; + } + // 4. write to following array in profile.json + this.setState( + { + userData: { + avatar: this.state.userData.avatar, + bio: this.state.userData.bio, + name: this.state.userData.name, + follows: [...this.state.userData.follows, followerData] + } + }, + () => this.changeUserData(this.state.userData) + ); + document.querySelector('#add-follower-input').value = ''; + }; + + updateUserData = e => { + e.preventDefault(); + this.changeUserData(this.state.userData); + }; + + userDataChange = (e, str) => { + this.setState({ + userData: { + ...this.state.userData, + [str]: e.target.value + } + }); + }; + + changeUserData = async userData => { + const archive = await new global.DatArchive(urlEnv()); + await archive.writeFile(`profile.json`, profileContents(userData)); + this.state.editProfile === true && this.toggleEdit(); + }; + + toggleEdit = () => + this.setState({ + editProfile: !this.state.editProfile + }); + + sortedPosts = posts => sortBy(posts, ['createdAt']).reverse(); + render() { - const sortedPosts = sortBy(this.state.posts, ['createdAt']).reverse(); - console.log('state', this.state); return (
@@ -145,7 +201,11 @@ class App extends Component { contentSelectionOpen={this.state.contentSelectionOpen} toggleContentSelection={this.toggleContentSelection} postDisplay={this.state.postDisplay} - posts={sortedPosts} + posts={this.sortedPosts( + this.state.postDisplay === 'theirs' + ? this.state.theirPosts + : this.state.posts + )} isOwner={this.state.isOwner} getPosts={this.getAllPostsSaved} togglePostDisplayFn={this.togglePostDisplay} @@ -175,6 +235,28 @@ class App extends Component { /> )} /> + ( + + )} + />
); diff --git a/src/containers/ContentViewContainer/index.js b/src/containers/ContentViewContainer/index.js index 40d8fc8..3184d87 100644 --- a/src/containers/ContentViewContainer/index.js +++ b/src/containers/ContentViewContainer/index.js @@ -4,6 +4,7 @@ import Header from '../../components/Header'; import ContentView from '../../components/ContentView'; import BrowserDetection from '../../components/SharedComponents/BrowserDetection'; import UserInfo from '../../components/SharedComponents/UserInfo'; + const ContentViewContainer = ({ loading, getPosts, diff --git a/src/containers/Settings/index.js b/src/containers/Settings/index.js new file mode 100644 index 0000000..f6c8542 --- /dev/null +++ b/src/containers/Settings/index.js @@ -0,0 +1,46 @@ +import React from 'react'; +import urlEnv from '../../utils/urlEnv'; + +import Header from '../../components/Header'; +import Follows from '../../components/Following/Follows'; +// import FollowSuggestions from '../../components/Following/FollowSuggestions'; +import NewFollow from '../../components/Following/NewFollow'; +import Profile from '../../components/SharedComponents/Profile'; + +const Settings = props => ( +
+
+
+
+
+

Profile Settings

+
props.toggleEdit()}> + pencil for edit +
+
+ +
+
+

Following

+ + +
+
+
+); + +export default Settings; diff --git a/src/index.css b/src/index.css index 1201578..51c08f7 100644 --- a/src/index.css +++ b/src/index.css @@ -16,8 +16,10 @@ body { max-width: 1040px; padding-top: 100px; } -.Post__Title { - padding-bottom: 30px; + +.Post .ContentItem__Title a { + font-size: 36px; + line-height: 40px; } .Header { background-color: rgba(255, 255, 255, 0.8); @@ -444,12 +446,10 @@ h5 { position: relative; width: 120px; } - .ImagePreview img { height: auto; width: 100%; } - .ImagePreview__Delete svg { cursor: pointer; position: absolute; @@ -458,3 +458,60 @@ h5 { transform: rotate(45deg); width: 25px; } +.UserInfo { + margin: 0 auto; + max-width: 1440px; + padding: 18px 20px; +} +.Settings { + padding-bottom: 100px; +} +.Settings__Container { + display: flex; + flex-direction: row; + margin: 0 auto; + max-width: 900px; + padding-top: 100px; +} +.Settings__Item { + flex-basis: 50%; + padding-right: 40px; +} +.Profile .label { + font-size: 12px; + font-weight: bold; + margin-bottom: 0; + margin-top: 30px; + text-transform: uppercase; +} +.Settings__Title { + max-width: 250px; + position: relative; +} +.Settings .Edit__Toggle { + cursor: pointer; + opacity: 0.7; + position: absolute; + right: 0; + top: -3px; + transform: rotate(0deg); + transition: opacity 200ms ease, transform 200ms ease; +} +.Settings .Edit__Toggle:hover { + opacity: 1; + transform: rotate(10deg); +} +.Settings .Edit__Toggle img { + height: auto; + width: 40px; +} +.Following { + margin-top: 20px; +} +.Following__Item a { + color: #000; + display: block; + font-size: 14px; + font-weight: bold; + padding: 10px 0; +} diff --git a/src/utils/fileContents.js b/src/utils/fileContents.js index c538f2e..81bddeb 100644 --- a/src/utils/fileContents.js +++ b/src/utils/fileContents.js @@ -17,6 +17,3 @@ const fileContents = ( }); export default fileContents; - -//--- Future additions/modifications -// "imageContent": "${postImage}", diff --git a/src/utils/following.js b/src/utils/following.js new file mode 100644 index 0000000..849fa60 --- /dev/null +++ b/src/utils/following.js @@ -0,0 +1,52 @@ +import urlEnv from './urlEnv'; + +const archive = new global.DatArchive(urlEnv()); + +export const queryFollowers = async () => { + // 1. get following list + const userData = await archive.readFile(`profile.json`); + const followingArray = JSON.parse(userData).follows; + // 2. map following users + if (followingArray.length > 0) { + followingArray.map(async follow => { + await queryFollowerPosts(follow); + }); + } +}; + +const queryFollowerPosts = async follow => { + let newArchive = new global.DatArchive(follow.url); + // 3. query posts from following users + let userArchive = await newArchive.readdir('/posts'); + if (userArchive.length > 0) { + userArchive.map(async post => { + let postResponse = await newArchive.readFile(`/posts/${post}`); + let postId = await JSON.parse(postResponse).postId; + // 4. check if post downloaded + // TODO - File will overwrite at this point... won't want double query though + + // 5. put posts into theirposts folder + await writePost(postResponse, postId); + }); + } +}; + +const writePost = async (post, postId) => { + await archive.writeFile(`/theirposts/${postId}.json`, post); +}; + +export const followURLCheck = async value => { + if ( + value.startsWith('dat://') && + (value.length === 70 || value.length === 71) + ) { + return value; + } else if ( + !value.startsWith('dat://') && + (value.length === 65 || value.length === 66) + ) { + return 'dat://' + value; + } else { + return ''; + } +}; diff --git a/src/utils/profileContents.js b/src/utils/profileContents.js new file mode 100644 index 0000000..7757e77 --- /dev/null +++ b/src/utils/profileContents.js @@ -0,0 +1,8 @@ +const profileContents = userData => `{ + "avatar": "${userData.avatar}", + "bio": "${userData.bio}", + "name": "${userData.name}", + "follows": ${JSON.stringify(userData.follows)} +}`; + +export default profileContents;