Feed js now loads from the API. Still have to finish posting.
This commit is contained in:
parent
15a5a95005
commit
59db25d3b1
|
|
@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
|
||||||
use App\Models\Friend;
|
use App\Models\Friend;
|
||||||
use App\Models\Shout;
|
use App\Models\Shout;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
@ -59,11 +60,19 @@ class FeedController extends Controller
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
|
|
||||||
|
$postDate = $post['updated_at'];
|
||||||
|
if(Carbon::now()->greaterThan($postDate->copy()->addDays(2)))
|
||||||
|
$postDate = $postDate->isoFormat('LLLL');
|
||||||
|
else
|
||||||
|
$postDate = $postDate->calendar();
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
array_push($posts['data'], [
|
array_push($posts['data'], [
|
||||||
'postId' => $post['id'],
|
'postId' => $post['id'],
|
||||||
'poster' => $poster,
|
'poster' => $poster,
|
||||||
'content' => $post['content'],
|
'content' => $post['content'],
|
||||||
'time' => $post['updated_at']
|
'time' => $postDate
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,14 @@ use Illuminate\Database\Eloquent\Model;
|
||||||
class Shout extends Model
|
class Shout extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
'updated_at' => 'datetime',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,11 @@ return [
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'paths' => ['api/*', 'sanctum/csrf-cookie'],
|
'paths' => ['*', 'sanctum/csrf-cookie'],
|
||||||
|
|
||||||
'allowed_methods' => ['*'],
|
'allowed_methods' => ['*'],
|
||||||
|
|
||||||
'allowed_origins' => ['*'],
|
'allowed_origins' => ['*.gtoria.net','*.gtoria.local'],
|
||||||
|
|
||||||
'allowed_origins_patterns' => [],
|
'allowed_origins_patterns' => [],
|
||||||
|
|
||||||
|
|
@ -29,6 +29,6 @@ return [
|
||||||
|
|
||||||
'max_age' => 0,
|
'max_age' => 0,
|
||||||
|
|
||||||
'supports_credentials' => false,
|
'supports_credentials' => true,
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,103 +1,132 @@
|
||||||
// © XlXi 2021
|
// © XlXi 2021
|
||||||
// Graphictoria 5
|
// Graphictoria 5
|
||||||
|
|
||||||
import { useState, useRef, useEffect } from 'react';
|
import { Component } from 'react';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
import Twemoji from 'react-twemoji';
|
import Twemoji from 'react-twemoji';
|
||||||
|
|
||||||
import { buildGenericApiUrl } from '../util/HTTP.js';
|
import { buildGenericApiUrl } from '../util/HTTP.js';
|
||||||
import Loader from './Loader';
|
import Loader from './Loader';
|
||||||
|
|
||||||
let posts = [
|
axios.defaults.withCredentials = true;
|
||||||
{
|
|
||||||
postId: 0,
|
|
||||||
poster: {
|
|
||||||
type: "User",
|
|
||||||
name: "XlXi",
|
|
||||||
icon: "fa-solid fa-gavel",
|
|
||||||
thumbnail: "https://www.gtoria.local/images/testing/headshot.png"
|
|
||||||
},
|
|
||||||
content: "gah 🥚in dammmmmm",
|
|
||||||
time: "Now"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
postId: 1,
|
|
||||||
poster: {
|
|
||||||
id: 1,
|
|
||||||
type: "Group",
|
|
||||||
name: "Graphictoria",
|
|
||||||
thumbnail: "https://www.gtoria.local/images/logo.png"
|
|
||||||
},
|
|
||||||
content: "test 2 😊",
|
|
||||||
time: "Now"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const Feed = () => {
|
class Feed extends Component {
|
||||||
const inputRef = useRef();
|
constructor(props) {
|
||||||
const submitRef = useRef();
|
super(props);
|
||||||
const feedRef = useRef();
|
this.state = {
|
||||||
const [feedLoaded, setFeedLoaded] = useState(true);
|
feedLoaded: false,
|
||||||
const [mouseHover, setMouseHover] = useState(-1);
|
loadingCursor: false,
|
||||||
|
feedPosts: [],
|
||||||
useEffect(() => {
|
mouseHover: -1
|
||||||
|
};
|
||||||
|
|
||||||
});
|
this.loadMore = this.loadMore.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
componentWillMount() {
|
||||||
<>
|
window.addEventListener('scroll', this.loadMore);
|
||||||
<h4>My Feed</h4>
|
}
|
||||||
<div className="card mb-2">
|
|
||||||
<div className="input-group p-2">
|
componentWillUnmount() {
|
||||||
<input ref={ inputRef } type="text" className="form-control" placeholder="What are you up to?" />
|
window.removeEventListener('scroll', this.loadMore);
|
||||||
<button ref={ submitRef } className="btn btn-secondary" type="submit">Share</button>
|
}
|
||||||
</div>
|
|
||||||
</div>
|
componentDidMount() {
|
||||||
{
|
axios.get(buildGenericApiUrl('api', 'feed/v1/list-json'))
|
||||||
feedLoaded ?
|
.then(res => {
|
||||||
(
|
const posts = res.data;
|
||||||
posts.length > 0 ?
|
|
||||||
<div className="card d-flex">
|
this.nextCursor = posts.next_cursor;
|
||||||
{
|
this.setState({ feedPosts: posts.data, feedLoaded: true });
|
||||||
posts.map(({ postId, poster, time, content }, index) =>
|
});
|
||||||
<>
|
}
|
||||||
<div className="row p-2" onMouseEnter={ () => setMouseHover(index) } onMouseLeave={ () => setMouseHover(-1) }>
|
|
||||||
<div className="col-3 col-sm-2 col-md-1">
|
// XlXi: https://stackoverflow.com/questions/57778950/how-to-load-more-search-results-when-scrolling-down-the-page-in-react-js
|
||||||
<a href={ buildGenericApiUrl('www', (poster.type == 'User' ? `users/${poster.name}/profile` : `groups/${poster.id}`)) }>
|
loadMore() {
|
||||||
{ poster.type == 'User' ?
|
// XlXi: Taking the height of the footer into account.
|
||||||
<img src={ poster.thumbnail } width="90" height="90" className="img-fluid border graphictora-user-circle" /> :
|
if (window.innerHeight + document.documentElement.scrollTop >= document.scrollingElement.scrollHeight-200) {
|
||||||
<img src={ poster.thumbnail } width="90" height="90" className="img-fluid" />
|
if (!!(this.nextCursor) && !this.state.loadingCursor) {
|
||||||
}
|
this.setState({ loadingCursor: true });
|
||||||
</a>
|
|
||||||
</div>
|
axios.get(buildGenericApiUrl('api', `feed/v1/list-json?cursor=${this.nextCursor}`))
|
||||||
<div className="col-9 col-sm-10 col-md-11">
|
.then(res => {
|
||||||
<div className="d-flex">
|
const posts = res.data;
|
||||||
<a href={ buildGenericApiUrl('www', (poster.type == 'User' ? `users/${poster.name}/profile` : `groups/${poster.id}`)) } className="text-decoration-none fw-bold me-auto">{ poster.name }{ poster.icon ? <> <i className={ poster.icon }></i></> : null }</a>
|
|
||||||
{ mouseHover == index ? <a href={ buildGenericApiUrl('www', `report/user-wall/${postId}`) } target="_blank" className="text-decoration-none link-danger me-2">Report <i className="fa-solid fa-circle-exclamation"></i></a> : null }
|
this.nextCursor = posts.next_cursor;
|
||||||
<p className="text-muted">{ time }</p>
|
this.setState({ feedPosts: this.state.feedPosts.concat(posts.data), loadingCursor: false });
|
||||||
</div>
|
});
|
||||||
<Twemoji options={{ className: 'twemoji', base: '/images/twemoji/', folder: 'svg', ext: '.svg' }}>
|
|
||||||
<p>{ content }</p>
|
|
||||||
</Twemoji>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{ posts.length != (index+1) ? <hr className="m-0" /> : null }
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
:
|
|
||||||
<div className="text-center mt-3">
|
|
||||||
<p className="text-muted">No posts were found. You could be the first!</p>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
:
|
|
||||||
<div className="d-flex">
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
</>
|
}
|
||||||
);
|
}
|
||||||
};
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h4>My Feed</h4>
|
||||||
|
<div className="card mb-2">
|
||||||
|
<div className="input-group p-2">
|
||||||
|
<input disabled={ !this.state.feedLoaded } type="text" className="form-control" placeholder="What are you up to?" />
|
||||||
|
<button disabled={ !this.state.feedLoaded } type="submit" className="btn btn-secondary">Share</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
this.state.feedLoaded ?
|
||||||
|
(
|
||||||
|
this.state.feedPosts.length > 0 ?
|
||||||
|
<>
|
||||||
|
<div className="card d-flex">
|
||||||
|
{
|
||||||
|
this.state.feedPosts.map(({ postId, poster, time, content }, index) =>
|
||||||
|
<>
|
||||||
|
<div className="row p-2" onMouseEnter={ () => this.setState({ mouseHover: index }) } onMouseLeave={ () => this.setState({ mouseHover: -1 }) }>
|
||||||
|
<div className="col-3 col-sm-2 col-md-1">
|
||||||
|
<a href={ buildGenericApiUrl('www', (poster.type == 'User' ? `users/${poster.name}/profile` : `groups/${poster.id}`)) }>
|
||||||
|
{ poster.type == 'User' ?
|
||||||
|
<img src={ poster.thumbnail } width="90" height="90" className="img-fluid border graphictora-user-circle" /> :
|
||||||
|
<img src={ poster.thumbnail } width="90" height="90" className="img-fluid" />
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="col-9 col-sm-10 col-md-11">
|
||||||
|
<div className="d-flex">
|
||||||
|
<a href={ buildGenericApiUrl('www', (poster.type == 'User' ? `users/${poster.name}/profile` : `groups/${poster.id}`)) } className="text-decoration-none fw-bold me-auto">{ poster.name }{ poster.icon ? <> <i className={ poster.icon }></i></> : null }</a>
|
||||||
|
{ this.state.mouseHover == index ? <a href={ buildGenericApiUrl('www', `report/user-wall/${postId}`) } target="_blank" className="text-decoration-none link-danger me-2">Report <i className="fa-solid fa-circle-exclamation"></i></a> : null }
|
||||||
|
<p className="text-muted">{ time }</p>
|
||||||
|
</div>
|
||||||
|
<Twemoji options={{ className: 'twemoji', base: '/images/twemoji/', folder: 'svg', ext: '.svg' }}>
|
||||||
|
<p>{ content }</p>
|
||||||
|
</Twemoji>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{ this.state.feedPosts.length != (index+1) ? <hr className="m-0" /> : null }
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
this.state.loadingCursor ?
|
||||||
|
<div className="d-flex mt-2">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
null
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
:
|
||||||
|
<div className="text-center mt-3">
|
||||||
|
<p className="text-muted">No posts were found. You could be the first!</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
:
|
||||||
|
<div className="d-flex">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default Feed;
|
export default Feed;
|
||||||
Loading…
Reference in New Issue