forum finished
everything should be finished. except for pagination, but fuck that it can wait.
This commit is contained in:
parent
6a97e9e52c
commit
3ad60c24b7
|
|
@ -98,7 +98,7 @@ class RegisterController extends Controller
|
|||
|
||||
setcookie('gtok', $sc, time()+(345600*30), "/", $_POST['host']);
|
||||
|
||||
return Response()->json('good');
|
||||
return Response()->json(['message'=>'Success!', 'badInputs'=>[]]);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,14 +34,39 @@ class Controller extends BaseController
|
|||
|
||||
$array = $user->toArray();
|
||||
|
||||
if ($user->Staff()) $array['power'] = $user->Staff()->power_level;
|
||||
|
||||
return Response()->json(["data"=>$array]);
|
||||
}
|
||||
|
||||
public function fetchCategories() {
|
||||
|
||||
$categories = Category::get();
|
||||
public function fetchCategoriesFP() {
|
||||
if (!isset($_COOKIE['gtok'])) {return Response()->json(["error"=>"No user."]);}
|
||||
|
||||
$POST = $_COOKIE['gtok'];
|
||||
|
||||
$user = User::where('token', $POST)->first();
|
||||
|
||||
if (!$user) {return Response()->json(["error"=>"No user."]);}
|
||||
|
||||
if ($user->Staff() && $user->Staff()->power_level >= 2) {$categories = Category::get();}else{$categories = Category::where('staffOnly', '0')->get();}
|
||||
|
||||
return Response()->json(["categories"=>$categories]);
|
||||
}
|
||||
|
||||
public function fetchCategories() {
|
||||
|
||||
if (!isset($_COOKIE['gtok'])) {return Response()->json(["error"=>"No user."]);}
|
||||
|
||||
$POST = $_COOKIE['gtok'];
|
||||
|
||||
$user = User::where('token', $POST)->first();
|
||||
|
||||
if (!$user) {return Response()->json(["error"=>"No user."]);}
|
||||
|
||||
$categories = Category::orderBy('staffOnly', 'desc')->get();
|
||||
|
||||
return Response()->json(["categories"=>$categories]);
|
||||
|
||||
return Response()->json(["data"=>$categories]);
|
||||
}
|
||||
|
||||
public function fetchCategory($id) {
|
||||
|
|
@ -50,7 +75,7 @@ class Controller extends BaseController
|
|||
|
||||
if (!$category) {return Response()->json(false);}
|
||||
|
||||
$posts = $category->posts()->paginate(20);
|
||||
$posts = $category->posts()->orderBy('pinned', 'desc')->orderBy('updated_at', 'desc')->paginate(20);
|
||||
|
||||
foreach ($posts as &$post) {
|
||||
$post['creator'] = User::where('id', $post['creator_id'])->first();
|
||||
|
|
@ -67,9 +92,19 @@ class Controller extends BaseController
|
|||
|
||||
$postA = $post->toArray();
|
||||
|
||||
$postA['creator'] = User::where('id', $postA['creator_id'])->first();;
|
||||
$realDate = explode('T', $postA['created_at'])[0];
|
||||
|
||||
$replies = $post->replies()->paginate(10);
|
||||
$postA['created_at'] = $realDate;
|
||||
|
||||
$postA['creator'] = User::where('id', $postA['creator_id'])->first();
|
||||
|
||||
$replies = $post->replies()->orderBy('pinned', 'desc')->orderBy('created_at', 'asc')->paginate(10);
|
||||
|
||||
foreach ($replies as &$reply) {
|
||||
$creator = User::where('id', $reply['creator_id'])->first();
|
||||
$reply['created_at'] = explode('T', $reply['created_at'])[0];
|
||||
$reply['creator_name'] = $creator->username;
|
||||
}
|
||||
|
||||
return Response()->json(["post"=>$postA,"replies"=>$replies]);
|
||||
}
|
||||
|
|
@ -124,7 +159,7 @@ class Controller extends BaseController
|
|||
|
||||
Auth::login($user);
|
||||
|
||||
return Response()->json('good');
|
||||
return Response()->json(['message'=>'Success!', 'badInputs'=>[]]);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
|
|||
use App\Providers\RouteServiceProvider;
|
||||
use App\Models\User;
|
||||
use App\Models\Post;
|
||||
use App\Models\Reply;
|
||||
use App\Models\Category;
|
||||
use Illuminate\Foundation\Auth\RegistersUsers;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
|
@ -20,10 +21,10 @@ class HomeController extends Controller
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
/*public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Show the application dashboard.
|
||||
|
|
@ -42,6 +43,7 @@ class HomeController extends Controller
|
|||
$valid = Validator::make($data, [
|
||||
'title' => ['required', 'string', 'min:3', 'max:38'],
|
||||
'body' => ['required', 'string', 'min:3', 'max:380'],
|
||||
'category' => ['required']
|
||||
]);
|
||||
|
||||
if ($valid->stopOnFirstFailure()->fails()) {
|
||||
|
|
@ -56,16 +58,62 @@ class HomeController extends Controller
|
|||
|
||||
if (!$user) {return Response()->json(['message'=>'User not found!', 'badInputs'=>['title']]);}
|
||||
|
||||
if (!isset($_POST['category'])) {return Response()->json(['message'=>'Category not found!', 'badInputs'=>['category']]);}
|
||||
|
||||
$categoryId = $_POST['category'];
|
||||
|
||||
$category = Category::where('id', $categoryId)->first();
|
||||
|
||||
if ($category->staffOnly == '1' && !$user->Staff()) {return Response()->json(['message'=>'You cant use that category.', 'badInputs'=>['category']]);}
|
||||
|
||||
$post = new Post;
|
||||
$post->title = $_POST['title'];
|
||||
$post->body = $_POST['body'];
|
||||
$post->creator_id = $_POST['creator_id'];
|
||||
//will add category support later
|
||||
$post->category_id = 1;
|
||||
$post->category_type = 'App\Models\Category';
|
||||
$post->save();
|
||||
$category->posts()->save($post);
|
||||
|
||||
return Response()->json('good');
|
||||
return Response()->json(['message'=>'Success!', 'badInputs'=>[], 'post_id'=>$post->id]);
|
||||
|
||||
}
|
||||
|
||||
public function createReply($id) {
|
||||
|
||||
$data = Request::all();
|
||||
|
||||
$valid = Validator::make($data, [
|
||||
'body' => ['required', 'string', 'min:3', 'max:380'],
|
||||
]);
|
||||
|
||||
if ($valid->stopOnFirstFailure()->fails()) {
|
||||
$error = $valid->errors()->first();
|
||||
$messages = $valid->messages()->get('*');
|
||||
return Response()->json(['message'=>$error, 'badInputs'=>[array_keys($messages)]]);
|
||||
}
|
||||
|
||||
if (!isset($_COOKIE['gtok'])) {return Response()->json(["error"=>"No user."]);}
|
||||
|
||||
$POST = $_COOKIE['gtok'];
|
||||
|
||||
$meta = User::where('token', $POST)->first();
|
||||
|
||||
if (!isset($_POST['creator_id'])) {return Response()->json(['message'=>'System error', 'badInputs'=>['title']]);}
|
||||
|
||||
$user = User::where('id', $_POST['creator_id'])->first();
|
||||
|
||||
if (!$user) {return Response()->json(['message'=>'User not found!', 'badInputs'=>['title']]);}
|
||||
|
||||
$post = Post::where('id', $id)->first();
|
||||
|
||||
if (!$post) {return Response()->json(['message'=>'Post not found!', 'badInputs'=>['body']]);}
|
||||
|
||||
if ($post->locked && $user->id != $meta->id) {return Response()->json(['message'=>'This post is locked!', 'badInputs'=>['body']]);}
|
||||
|
||||
$reply = new Reply;
|
||||
$reply->body = $_POST['body'];
|
||||
$reply->creator_id = $user->id;
|
||||
$post->replies()->save($reply);
|
||||
|
||||
return Response()->json(['message'=>'Success!', 'badInputs'=>[], 'post_id'=>$post->id]);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Staff extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'staff';
|
||||
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
use App\Models\Staff;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
|
|
@ -43,4 +44,10 @@ class User extends Authenticatable
|
|||
protected $casts = [
|
||||
'email_verified_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function Staff() {
|
||||
$staff = Staff::where('user_id', $this->id)->first();
|
||||
return $staff;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateStaffTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('staff', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('power_level')->default(1);
|
||||
$table->string('user_id');
|
||||
$table->string('staff_title')->default('Moderator');
|
||||
/* Obviously this isn't the most elegant way of designing a staff system, but ill revamp it later down the road. */
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('staff');
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// Graphictoria 5
|
||||
|
||||
import axios from "axios";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import Config from '../config.js';
|
||||
|
||||
axios.defaults.withCredentials = true
|
||||
|
|
@ -23,8 +24,9 @@ export function CreateAccount(form)
|
|||
badInputs=res.badInputs;
|
||||
resolve({message: res.message, inputs: res.badInputs});
|
||||
return;
|
||||
}else{
|
||||
resolve("good")
|
||||
}
|
||||
resolve("good");
|
||||
}).catch(error=>{console.log(error);});
|
||||
|
||||
});
|
||||
|
|
@ -44,8 +46,9 @@ export function LoginToAccount(form) {
|
|||
badInputs=res.badInputs;
|
||||
resolve({message: res.message, inputs: res.badInputs});
|
||||
return;
|
||||
}else{
|
||||
resolve("good")
|
||||
}
|
||||
resolve("good");
|
||||
}).catch(error=>{console.log(error);});
|
||||
|
||||
});
|
||||
|
|
@ -59,6 +62,7 @@ export function CreateForum(form) {
|
|||
|
||||
return new Promise(async (resolve, reject)=>{
|
||||
axios.post(`${protocol}apis.${url}/api/create/forum`, body, {headers: {'X-CSRF-TOKEN': document.querySelector(`meta[name="csrf-token"]`).content, "X-Requested-With":"XMLHttpRequest"}}).then(data=>{
|
||||
const history = useHistory();
|
||||
const res = data.data;
|
||||
if (res.badInputs.length >= 1) {
|
||||
badInputs=res.badInputs;
|
||||
|
|
@ -69,7 +73,7 @@ export function CreateForum(form) {
|
|||
});
|
||||
}
|
||||
|
||||
export function LogoutOfAccount() {
|
||||
/*export function LogoutOfAccount() {
|
||||
|
||||
const body = form;
|
||||
var badInputs = [];
|
||||
|
|
@ -79,4 +83,4 @@ export function LogoutOfAccount() {
|
|||
resolve("good");
|
||||
}).catch(error=>{console.log(error);});
|
||||
|
||||
}
|
||||
}*/
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { useState, useEffect } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
|
||||
import { PageTransition } from '@steveeeie/react-page-transition';
|
||||
import { PageTransition, __esModule } from '@steveeeie/react-page-transition';
|
||||
import { GuardProvider, GuardedRoute } from 'react-router-guards'
|
||||
|
||||
import Config from '../config.js';
|
||||
|
|
@ -32,6 +32,7 @@ import Dashboard from '../pages/Dashboard.js';
|
|||
import Forum from '../pages/Forum.js';
|
||||
import Post from '../pages/Post.js';
|
||||
import CreatePost from '../pages/CreatePost.js';
|
||||
import CreateReply from '../pages/CreateReply.js';
|
||||
|
||||
axios.defaults.withCredentials = true
|
||||
|
||||
|
|
@ -92,6 +93,9 @@ const App = () => {
|
|||
}else if (to.meta.guest) {
|
||||
if (!user) {next();}
|
||||
next.redirect(`/home`);
|
||||
}else if (to.meta.staff) {
|
||||
if (user && user.power) {next();}
|
||||
next.redirect(`/`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -145,6 +149,10 @@ const App = () => {
|
|||
<CreatePost user={user}/>
|
||||
</GuardedRoute>
|
||||
|
||||
<GuardedRoute exact path="/forum/reply/:id" meta={{auth: true}}>
|
||||
<CreateReply user={user}/>
|
||||
</GuardedRoute>
|
||||
|
||||
<Route exact path="/forum/category/:id">
|
||||
<Forum user={user}/>
|
||||
</Route>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import React from 'react';
|
|||
export const Card = (props) => {
|
||||
return (
|
||||
<div className="container graphictoria-center-vh">
|
||||
<div className="card graphictoria-small-card shadow-sm">
|
||||
<div className={`card graphictoria-small-card shadow-sm ${props.className}`}>
|
||||
<div className={`card-body ${props.padding? `p5r` : null} text-center`}>
|
||||
{ props.children }
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// Graphictoria 5
|
||||
|
||||
import React, {useState} from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
|
||||
import ReCAPTCHA from 'react-google-recaptcha';
|
||||
import { CreateAccount, LoginToAccount } from '../../Helpers/Auth';
|
||||
|
|
@ -11,8 +11,8 @@ import Loader from '../../Components/Loader';
|
|||
const LoginForm = (props) => {
|
||||
|
||||
const [waitingForSubmission, setWaitingForSubmission] = useState(false);
|
||||
|
||||
const [validity, setValidity] = useState({error: false, message: ``, inputs: []});
|
||||
const history = useHistory();
|
||||
|
||||
async function SubmitLogin(form)
|
||||
{
|
||||
|
|
@ -22,8 +22,9 @@ const LoginForm = (props) => {
|
|||
setValidity({error: true, message:res.message, inputs: res.inputs});
|
||||
setTimeout(()=>{setValidity({...validity, error: false, inputs: res.inputs});}, 4000);
|
||||
return;
|
||||
}else{
|
||||
window.location.replace(`/home`);
|
||||
}
|
||||
window.location.reload();
|
||||
}).catch(error=>console.log(error));
|
||||
setWaitingForSubmission(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// Graphictoria 5
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
|
||||
import ReCAPTCHA from 'react-google-recaptcha';
|
||||
|
||||
|
|
@ -34,8 +34,8 @@ const RegisterForm = (props) => {
|
|||
];
|
||||
|
||||
const [waitingForSubmission, setWaitingForSubmission] = useState(false);
|
||||
|
||||
const [validity, setValidity] = useState({error: false, message: ``, inputs: []});
|
||||
const history = useHistory();
|
||||
|
||||
async function SubmitRegistration(form)
|
||||
{
|
||||
|
|
@ -46,8 +46,9 @@ const RegisterForm = (props) => {
|
|||
setValidity({error: true, message:res.message, inputs: res.inputs});
|
||||
setTimeout(()=>{setValidity({...validity, error: false, inputs: res.inputs});}, 4000);
|
||||
return;
|
||||
}else{
|
||||
window.location.replace(`/home`);
|
||||
}
|
||||
window.location.replace(`/home`);
|
||||
}).catch(error=>console.log(error));
|
||||
setWaitingForSubmission(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// © XlXi 2021
|
||||
// Graphictoria 5
|
||||
|
||||
import React, {useState} from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
|
||||
import ReCAPTCHA from 'react-google-recaptcha';
|
||||
import { CreateAccount, LoginToAccount, CreateForum } from '../Helpers/Auth';
|
||||
|
|
@ -11,6 +11,7 @@ import { getCookie } from '../helpers/utils';
|
|||
|
||||
import axios from "axios";
|
||||
import Config from '../config.js';
|
||||
import { Card, CardTitle } from '../Layouts/Card';
|
||||
|
||||
axios.defaults.withCredentials = true
|
||||
|
||||
|
|
@ -21,7 +22,16 @@ const CreatePost = (props) => {
|
|||
|
||||
const [waitingForSubmission, setWaitingForSubmission] = useState(false);
|
||||
const [validity, setValidity] = useState({error: false, message: ``, inputs: []});
|
||||
const [categories, setCategoires] = useState({loading: true, categories: []});
|
||||
const user = props.user;
|
||||
const history = useHistory();
|
||||
|
||||
useEffect(async()=>{
|
||||
await axios.get(`${protocol}apis.${url}/fetch/categories/post`, null, {headers: {'X-CSRF-TOKEN': document.querySelector(`meta[name="csrf-token"]`).content, "X-Requested-With":"XMLHttpRequest"}}).then(data=>{
|
||||
const res = data.data;
|
||||
setCategoires({loading: false, categories: res.categories});
|
||||
}).catch(error=>{console.log(error);});
|
||||
}, []);
|
||||
|
||||
async function SubmitForm(form)
|
||||
{
|
||||
|
|
@ -33,18 +43,18 @@ const CreatePost = (props) => {
|
|||
if (res.badInputs.length >= 1) {
|
||||
setValidity({error: true, message:res.message, inputs: res.badInputs});
|
||||
setTimeout(()=>{setValidity({...validity, error: false, inputs: res.badInputs});}, 4000);
|
||||
return;
|
||||
}else{
|
||||
history.push(`/forum/post/${res.post_id}`);
|
||||
}
|
||||
window.location.replace(`/forum`);
|
||||
}).catch(error=>{console.log(error);});
|
||||
setWaitingForSubmission(false);
|
||||
}
|
||||
|
||||
return (
|
||||
waitingForSubmission ? <Loader/> :
|
||||
<div className={`flex column jcc alc w-100`}>
|
||||
<div className={`flex card card-body column alc w-40`}>
|
||||
<div className={`flex row`}>
|
||||
waitingForSubmission && !categories.loading? <Loader/> :
|
||||
<Card>
|
||||
<CardTitle>Create a new Post</CardTitle>
|
||||
<div className="p-2 row">
|
||||
<div className="col-md-8 mb-2">
|
||||
{validity.error?
|
||||
<div className={`px-5 mb-10`}>
|
||||
|
|
@ -56,6 +66,11 @@ const CreatePost = (props) => {
|
|||
<form onSubmit={(e)=>{e.preventDefault();SubmitForm(new FormData(e.target));}} class="fs">
|
||||
<input type="username" className={`form-control mb-4 ${(validity.inputs.find(input=>input == `title`)? `is-invalid` : ``)}`} placeholder="Title" name="title"/>
|
||||
<textarea type="username" className={`form-control mb-4 ${(validity.inputs.find(input=>input == `body`)? `is-invalid` : ``)}`} placeholder="Body" name="body"></textarea>
|
||||
<select class="form-select" name={`category`}>
|
||||
{categories.categories.map(category=>(
|
||||
<option value={category.id}>{category.title}</option>
|
||||
))}
|
||||
</select>
|
||||
<div className="d-flex mb-3">
|
||||
<ReCAPTCHA
|
||||
sitekey="6LeyHsUbAAAAAJ9smf-als-hXqrg7a-lHZ950-fL"
|
||||
|
|
@ -70,8 +85,7 @@ const CreatePost = (props) => {
|
|||
<p>Before you make a post, be sure to read the <Link to={`/forum/rules`}>rules</Link>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
// © XlXi 2021
|
||||
// Graphictoria 5
|
||||
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import { Link, useHistory, useParams } from 'react-router-dom';
|
||||
|
||||
import ReCAPTCHA from 'react-google-recaptcha';
|
||||
import { CreateAccount, LoginToAccount, CreateForum } from '../Helpers/Auth';
|
||||
import Loader from '../Components/Loader';
|
||||
import { getCookie } from '../helpers/utils';
|
||||
import { Card, CardTitle } from '../Layouts/Card';
|
||||
|
||||
import axios from "axios";
|
||||
import Config from '../config.js';
|
||||
|
||||
axios.defaults.withCredentials = true
|
||||
|
||||
var url = Config.BaseUrl.replace('http://', '');
|
||||
var protocol = Config.Protocol;
|
||||
|
||||
const CreateReply = (props) => {
|
||||
|
||||
const [waitingForSubmission, setWaitingForSubmission] = useState(false);
|
||||
const [validity, setValidity] = useState({error: false, message: ``, inputs: []});
|
||||
const [post, setPost] = useState({loading: true, post: []});
|
||||
const user = props.user;
|
||||
const postId = useParams().id;
|
||||
const history = useHistory();
|
||||
|
||||
useEffect(async()=>{
|
||||
await axios.get(`${protocol}apis.${url}/fetch/post/${postId}`, {headers: {"X-Requested-With":"XMLHttpRequest"}}).then(data=>{
|
||||
if (!data.data) {history.push(`/forum`);}
|
||||
const res = data.data;
|
||||
setPost({loading: false, post: res.post});
|
||||
}).catch(error=>{console.log(error);});
|
||||
}, []);
|
||||
|
||||
async function SubmitForm(form)
|
||||
{
|
||||
form.append('creator_id', user.id);
|
||||
setWaitingForSubmission(true);
|
||||
await axios.post(`${protocol}apis.${url}/api/create/reply/${post.post.id}`, form, {headers: {'X-CSRF-TOKEN': document.querySelector(`meta[name="csrf-token"]`).content, "X-Requested-With":"XMLHttpRequest"}}).then(data=>{
|
||||
const res = data.data;
|
||||
console.log(res);
|
||||
if (res.badInputs.length >= 1) {
|
||||
setValidity({error: true, message:res.message, inputs: res.badInputs});
|
||||
setTimeout(()=>{setValidity({...validity, error: false, inputs: res.badInputs});}, 4000);
|
||||
}else{
|
||||
history.push(`/forum/post/${res.post_id}`);
|
||||
}
|
||||
}).catch(error=>{console.log(error);});
|
||||
setWaitingForSubmission(false);
|
||||
}
|
||||
|
||||
return (
|
||||
waitingForSubmission && !post.loading? <Loader/> :
|
||||
<Card>
|
||||
<CardTitle>Reply to '{post.post.title}'</CardTitle>
|
||||
<div className="p-2 row">
|
||||
<div className="col-md-8 mb-2">
|
||||
{validity.error?
|
||||
<div className={`px-5 mb-10`}>
|
||||
<div className={`error-dialog`}>
|
||||
<p className={`mb-0`}>{validity.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
: null}
|
||||
<form onSubmit={(e)=>{e.preventDefault();SubmitForm(new FormData(e.target));}} class="fs">
|
||||
<textarea type="username" className={`form-control mb-4 ${(validity.inputs.find(input=>input == `body`)? `is-invalid` : ``)}`} placeholder="Body" name="body"></textarea>
|
||||
<div className="d-flex mb-3">
|
||||
<ReCAPTCHA
|
||||
sitekey="6LeyHsUbAAAAAJ9smf-als-hXqrg7a-lHZ950-fL"
|
||||
className="mx-auto"
|
||||
/>
|
||||
</div>
|
||||
<button className="btn btn-primary px-5" type={`submit`}>REPLY!</button><br/>
|
||||
</form>
|
||||
</div>
|
||||
<div className="col">
|
||||
<h5><bold>Read the rules before replying!</bold></h5>
|
||||
<p>Before you make a post, be sure to read the <Link to={`/forum/rules`}>rules</Link>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateReply;
|
||||
|
|
@ -30,7 +30,7 @@ const Forum = (props) => {
|
|||
|
||||
const fetchCategories = async () => {
|
||||
await axios.get(`${protocol}apis.${url}/fetch/categories`, {headers: {"X-Requested-With":"XMLHttpRequest"}}).then(data=>{
|
||||
setCategoires(data.data.data);
|
||||
setCategoires(data.data.categories);
|
||||
}).catch(error=>{console.log(error);});
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ const Forum = (props) => {
|
|||
<p>{category.description}</p>
|
||||
{user?
|
||||
<div className={`flex row justify-content-center`}>
|
||||
<Link className={`btn btn-success w-20`} to={`/forum/post`}>Create a post</Link>
|
||||
{category.staffOnly == 1 && !user.power ? null : <Link className={`btn btn-success w-20`} to={`/forum/post`}>Create a post</Link>}
|
||||
</div>
|
||||
: null}
|
||||
</div>
|
||||
|
|
@ -87,8 +87,8 @@ const Forum = (props) => {
|
|||
<div className={`flex row m-0`}>
|
||||
<h5 className={`m-0`}>{post.title}</h5>
|
||||
<div className={`row fs12`}>
|
||||
<p>Posted by:</p>
|
||||
<Link to={`/user/${post.creator.id}`}>{post.creator.username}</Link>
|
||||
<p className={`w-fit-content`}>Posted by:</p>
|
||||
<Link to={`/user/${post.creator.id}`} className={`w-fit-content padding-none`}>{post.creator.username}</Link>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -23,11 +23,13 @@ const Post = (props) => {
|
|||
const [state, setState] = useState({offline: false, loading: true});
|
||||
const [post, setPost] = useState({post: [], replies: {replies: [], meta: [], currentPage: 0}});
|
||||
const user = props.user;
|
||||
const history = useHistory();
|
||||
|
||||
const fetchPost = async () => {
|
||||
await axios.get(`${protocol}apis.${url}/fetch/post/${id}`, {headers: {"X-Requested-With":"XMLHttpRequest"}}).then(data=>{
|
||||
if (!data.data) {window.location.href=`/forum`;return;}
|
||||
setPost({post: data.data.post, replies: {replies: data.data.replies.data, meta: data.data.replies, currentPage: 0}});
|
||||
if (!data.data) {history.push(`/forum`);}
|
||||
const res = data.data;
|
||||
setPost({post: res.post, replies: {replies: res.replies.data, meta: res.replies, currentPage: 0}});
|
||||
}).catch(error=>{console.log(error);});
|
||||
}
|
||||
|
||||
|
|
@ -42,18 +44,68 @@ const Post = (props) => {
|
|||
?
|
||||
<Loader />
|
||||
:
|
||||
<div className={`flex jcc alc w-100 column`}>
|
||||
<div className={`graphic-post w-40`}>
|
||||
{/* Time&Date goes here. */}
|
||||
<div className={`flex w-100`}>
|
||||
<div className={`flex column mr-15`}>
|
||||
<p>Posted by:</p>
|
||||
<Link to={`/user/${post.post.creator.id}`}>{post.post.creator.username}</Link>
|
||||
<div className={`flex w-100 column jcc alc`}>
|
||||
{post.post.locked == 1?
|
||||
<div className={`container`}>
|
||||
<div className={`error-dialog graphictoria-small-card`}>
|
||||
<p className={`mb-0`}>This post is locked!</p>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className={`container`}>
|
||||
<div className={`graphictoria-small-card row`}>
|
||||
{user && user.username? <Link className="btn btn-primary px-5 w-fit-content mb-15" to={`/forum/reply/${post.post.id}`}>Reply</Link> : <p>Sign in to reply!</p>}
|
||||
</div>
|
||||
</div>}
|
||||
<Card>
|
||||
<div className={`flex w-100 column`}>
|
||||
<div className={`flex row fs12`}>
|
||||
<div className={`row w-fit-content`}>
|
||||
<p className={`w-fit-content`}>Post Title:</p>
|
||||
<p className={`w-fit-content padding-none`}><i><strong>'{post.post.title}'</strong></i></p>
|
||||
</div>
|
||||
<div className={`row w-fit-content`}>
|
||||
<p className={`w-fit-content`}>Date posted:</p>
|
||||
<p className={`w-fit-content padding-none`}>{post.post.created_at}</p>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div className={`flex row`}>
|
||||
<p className={`m-0`}>{post.post.body}</p>
|
||||
<div className={`flex column jcc alc col-3`}>
|
||||
<p className={`mb-10`}>[Avatar.]</p>
|
||||
<Link to={`/user/${post.post.creator.id}`}>{post.post.creator.username}</Link>
|
||||
</div>
|
||||
<div className={`col text-left`}>
|
||||
<p className={`m-0`}>{post.post.body}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<div className={`container`}><hr className={`graphictoria-small-card mt-15 mb-15`}/></div>
|
||||
{post.replies.replies.length <= 0 && post.post.locked != 1? <p className={`w-100 text-center`}>There isn't any replies to this post yet!</p> : null}
|
||||
<div className={`flex column w-100`}>
|
||||
{post.replies.replies.map(reply=>(
|
||||
<Card>
|
||||
<div className={`flex w-100 column`}>
|
||||
<div className={`flex row fs12`}>
|
||||
<div className={`row w-fit-content`}>
|
||||
<p className={`w-fit-content`}>Date posted:</p>
|
||||
<p className={`w-fit-content padding-none`}>{reply.created_at}</p>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div className={`flex row`}>
|
||||
<div className={`flex column jcc alc col-3`}>
|
||||
<p className={`mb-10`}>[Avatar.]</p>
|
||||
<Link to={`/user/${reply.creator_id}`}>{reply.creator_name}</Link>
|
||||
</div>
|
||||
<div className={`col text-left`}>
|
||||
<p className={`m-0`}>{reply.body}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -898,6 +898,14 @@ a.list-group-item {
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.w-fit-content {
|
||||
width: fit-content !important;
|
||||
}
|
||||
|
||||
.h-fit-content {
|
||||
height: fit-content !important;
|
||||
}
|
||||
|
||||
.mr-15 {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
|
@ -914,6 +922,30 @@ p {
|
|||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.padding-none {
|
||||
padding: 0px !important
|
||||
}
|
||||
|
||||
.text-left {
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right !important;
|
||||
}
|
||||
|
||||
.mt-15 {
|
||||
margin-top: 15px !important;
|
||||
}
|
||||
|
||||
.mb-15 {
|
||||
margin-bottom: 15px !important;
|
||||
}
|
||||
|
||||
.graphic-post {
|
||||
padding: 1rem 1rem;
|
||||
text-align: start;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ Route::get('/games/metadata', 'GamesController@isAvailable');
|
|||
|
||||
Route::get('/fetch/categories', 'Controller@fetchCategories');
|
||||
|
||||
Route::get('/fetch/categories/post', 'Controller@fetchCategoriesFP');
|
||||
|
||||
Route::get('/fetch/category/{id}', 'Controller@fetchCategory');
|
||||
|
||||
Route::get('/fetch/posts/{id}', 'Controller@fetchPosts');
|
||||
|
|
@ -45,6 +47,8 @@ Route::post('/account/login', 'Controller@login');
|
|||
|
||||
Route::post('/api/create/forum', 'HomeController@createPost');
|
||||
|
||||
Route::post('/api/create/reply/{id}', 'HomeController@createReply');
|
||||
|
||||
Route::fallback(function(){
|
||||
return response('{"errors":[{"code":404,"message":"NotFound"}]}', 404)
|
||||
->header('Cache-Control', 'private')
|
||||
|
|
|
|||
Loading…
Reference in New Issue