started catalog

cock
This commit is contained in:
xander 2022-03-23 11:02:23 -12:00
parent 6ec79d2f36
commit 97d08c62d5
16 changed files with 413 additions and 11 deletions

View File

@ -12,6 +12,9 @@ use App\Models\Category;
use App\Models\Post;
use App\Models\Reply;
use App\Models\Staff;
use App\Models\CatalogCategory;
use App\Models\Item;
use App\Models\Inventory;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
@ -41,6 +44,8 @@ class Controller extends BaseController
$array = $user->toArray();
$staff = Staff::where('user_id', $user->id)->first();
if ($staff) {$array['power'] = $staff->power_level;}
$array['bank'] = $user->bank;
$array['email'] = $user->email;
return Response()->json(["data"=>$array]);
break;
case "fetchedUser":
@ -86,6 +91,29 @@ class Controller extends BaseController
}
public function fetchCategoriesCatalog() {
$categories = CatalogCategory::get();
return Response()->json(["categories"=>$categories]);
}
public function fetchCategoryCatalog($id) {
$category = CatalogCategory::where('id', $id)->first();
if (!$category) {return Response()->json(false);}
$items = $category->items()->orderBy('updated_at', 'desc')->paginate(25);
foreach ($items as &$item) {
$item['creator'] = User::where('id', $item['creator_id'])->first();
}
return Response()->json(["data"=>$category, "items"=>$items]);
}
public function fetchCategory($id) {
$category = Category::where('id', $id)->first();

View File

@ -0,0 +1,20 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class CatalogCategory extends Model
{
use HasFactory;
protected $table = 'catalog_categories';
function items()
{
return $this->morphMany('App\Models\Item', 'category');
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Inventory extends Model
{
use HasFactory;
protected $table = 'inventories';
public function item() {
return $this->belongsTo(Item::class);
}
}

15
web/app/Models/Item.php Normal file
View File

@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Item extends Model
{
use HasFactory;
protected $table = 'items';
}

View File

@ -33,7 +33,9 @@ class User extends Authenticatable
'password',
'remember_token',
'token',
'email'
'email',
'email_verified_at',
'bank'
];
/**
@ -49,5 +51,9 @@ class User extends Authenticatable
$staff = Staff::where('user_id', $this->id)->first();
return $staff;
}
public function inventory() {
return $this->morphMany('App\Models\Inventory', 'owner');
}
}

View File

@ -20,6 +20,7 @@ class CreateUsersTable extends Migration
$table->timestamp('email_verified_at')->default(null);
$table->string('password');
$table->string('token');
$table->integer('bank')->default(150);
$table->string('about')->default(null);
$table->timestamps();
});

View File

@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateItemsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('items', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('description');
$table->string('thumbnail');
$table->integer('creator_id');
$table->integer('starting_price')->default(5);
$table->integer('current_price')->default(5);
$table->integer('category_id')->default(1);
$table->string('category_type');
//may need to add more later idk.
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('items');
}
}

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateInventoriesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('inventories', function (Blueprint $table) {
$table->id();
$table->string('item_id');
$table->string('owner_id');
$table->string('owner_type');
$table->string('uid'); //unique id | used for limiteds, the original id of the inventory row. once set, it never changes
$table->boolean('status')->default(true);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('inventories');
}
}

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCatalogCategoriesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('catalog_categories', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('description');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('catalog_categories');
}
}

View File

@ -51,13 +51,16 @@ const Navbar = (props) => {
<>
<SearchBar />
{props.user?
<li className="nav-item dropdown">
<button className="btn btn-secondary nav-link dropdown-toggle" href="#" id="graphictoria-nav-dropdown" role="button" data-bs-toggle="dropdown" area-expanded="false">{props.user.username}</button>
<ul className="dropdown-menu graphictoria-nav-dropdown" area-labelledby="graphictoria-nav-dropdown">
<li><NavLink className="dropdown-item" to="/auth/settings">Settings</NavLink></li>
<li><a className="dropdown-item" href={`/account/logout`}>Logout</a></li>
</ul>
</li> : <Link className="btn btn-success" to="/login">Login / Sign up</Link>}
<div className={`flex row`}>
<div className={`flex row col flex alc`}>Bank: ${props.user.bank}</div>
<li className="nav-item dropdown col flex alc">
<button className="btn btn-secondary nav-link dropdown-toggle" href="#" id="graphictoria-nav-dropdown" role="button" data-bs-toggle="dropdown" area-expanded="false">{props.user.username}</button>
<ul className="dropdown-menu graphictoria-nav-dropdown" area-labelledby="graphictoria-nav-dropdown">
<li><NavLink className="dropdown-item" to="/auth/settings">Settings</NavLink></li>
<li><a className="dropdown-item" href={`/account/logout`}>Logout</a></li>
</ul>
</li>
</div> : <Link className="btn btn-success" to="/login">Login / Sign up</Link>}
</>
:
null

View File

@ -35,6 +35,7 @@ import CreatePost from '../pages/CreatePost.js';
import CreateReply from '../pages/CreateReply.js';
import Settings from '../pages/Settings.js';
import User from '../pages/User.js';
import Catalog from '../pages/Catalog.js';
axios.defaults.withCredentials = true
@ -155,6 +156,14 @@ const App = () => {
<Forum user={user}/>
</Route>
<Route exact path="/catalog">
<Catalog user={user}/>
</Route>
<Route exact path="/catalog/category/:id">
<Catalog user={user}/>
</Route>
<GuardedRoute exact path="/forum/post" meta={{auth: true}}>
<CreatePost user={user}/>
</GuardedRoute>

131
web/resources/js/pages/Catalog.js vendored Normal file
View File

@ -0,0 +1,131 @@
// © XlXi 2021
// Graphictoria 5
import axios from 'axios';
import React, { useEffect, useState } from "react";
import { Link, useHistory, useParams } from "react-router-dom";
import Config from '../config.js';
import SetTitle from "../Helpers/Title.js";
import Loader from '../Components/Loader.js';
import { GenericErrorModal } from './Errors.js';
import { Card, CardTitle } from '../Layouts/Card.js';
import { paginate } from '../helpers/utils.js';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
var url = Config.BaseUrl.replace('http://', '');
var protocol = Config.Protocol;
const Catalog = (props) => {
var id = useParams().id;
const [state, setState] = useState({offline: false, loading: true});
const [categories, setCategoires] = useState([]);
const [category, setCategory] = useState([]);
const [items, setItems] = useState({items: [], currentPage: 1, meta: []});
const user = props.user;
if (!id) id = 1;
const fetchCategories = async () => {
await axios.get(`${protocol}apis.${url}/fetch/categories/catalog`, {headers: {"X-Requested-With":"XMLHttpRequest"}}).then(data=>{
setCategoires(data.data.categories);
}).catch(error=>{console.log(error);});
}
const fetchCategory = async () => {
await axios.get(`${protocol}apis.${url}/fetch/category/catalog/${id}?page=${items.currentPage}`, {headers: {"X-Requested-With":"XMLHttpRequest"}}).then(data=>{
if (!data.data) {window.location.href=`/forum`;return;}
setCategory(data.data.data);
setItems({...items, items: data.data.items.data, meta: data.data.items});
}).catch(error=>{console.log(error);});
}
const paginateitems = async (decision) => {
paginate(decision, items.currentPage, items.meta).then(res=>{
switch(res){
case "increase":
setItems({...items, currentPage: items.currentPage+1});
break;
case "decrease":
setItems({...items, currentPage: items.currentPage-1});
break;
default:
break;
}
}).catch(error=>console.log(error));
}
useEffect(async ()=>{
SetTitle(`Catalog`);
await fetchCategory();
await fetchCategories();
setState({...state, loading: false});
}, []);
useEffect(async()=>{
setState({...state, loading: true});
await fetchCategory();
setState({...state, loading: false});
}, [items.currentPage]);
return (
state.loading || categories.length <= 0
?
<Loader />
:
<div className={`flex jcc alc w-100 column`}>
<div className="graphictoria-nav-splitter"></div>
<div className={`row w-60`}>
<div className={`col-3 justify-content-center flex-column`}>
<div>
<h4>Categories:</h4>
{categories.map(category=>(
<>
<Link to={`/catalog/category/${category.id}`}>{category.title}</Link><br/>
</>
))}
</div>
<div className="graphictoria-nav-splitter"></div>
<div>
<h4>Options:</h4>
<div className={`flex flex-column`}>
<h6>Search for an item:</h6>
<input placeholder={`temp`}/>
</div>
</div>
</div>
<div className={`col justify-content-center`}>
{items.items.length <= 0 ? <p>There are currently no items!</p> : null}
<div className={`flex flex-row flex-wrap`}>
{items.items.map(item=>(
<>
<Link to={`/item/${item.id}`} className={`flex graphic-post-column col-3`}>
<div className={`flex column mb-10 alc`}>
[Thumbnail.]
</div>
<div className={`flex flex-column m-0`}>
<div className={`flex row w-fit-content`}><h6 className={`m-0 mr-15 fs13`}>{item.title}</h6></div>
<div className={`row fs15 w-fit-content`}>
<p className={`w-fit-content`}>${item.current_price}</p>
</div>
</div>
</Link>
</>
))}
</div>
{items.items.length >= 1?
<div className={`w-100 jcc alc row mt-15`}>
{items.currentPage >= 2? <button className={`w-fit-content btn btn-primary mr-15`} onClick={(e)=>{paginateitems(true);}}>Previous Page</button> : null}
{items.currentPage < items.meta.last_page? <button className={`w-fit-content btn btn-primary`} onClick={(e)=>{paginateitems(false);}}>Next Page</button> : null}
</div> : null}
</div>
</div>
</div>
);
}
export default Catalog;

View File

@ -73,7 +73,7 @@ const Forum = (props) => {
}, [posts.currentPage]);
return (
state.loading
state.loading || categories.length <= 0
?
<Loader />
:

View File

@ -68,8 +68,8 @@ const Settings = (props) => {
</div>
<div className="graphictoria-nav-splitter"></div>
{validity.error?
<div className={`px-5 mb-10 w-60`}>
<div className={`error-dialog w-60`}>
<div className={`px-5 mb-10 w-60 justify-content-center align-items-center`}>
<div className={`error-dialog w-100`}>
<p className={`mb-0`}>{validity.message}</p>
</div>
</div>

View File

@ -330,6 +330,7 @@ html {
.graphictoria-nav-splitter {
margin-top: 16px;
margin-bottom: 16px !important;
}
.graphictoria-search, #graphictoria-search-dropdown {
@ -928,10 +929,34 @@ p {
margin: 0px !important;
}
.fs10 {
font-size: 10px !important;
}
.fs11 {
font-size: 11px !important;
}
.fs12 {
font-size: 12px !important;
}
.fs13 {
font-size: 13px !important;
}
.fs14 {
font-size: 14px !important;
}
.fs15 {
font-size: 15px !important;
}
.fs16 {
font-size: 16px !important;
}
.padding-none {
padding: 0px !important
}
@ -956,6 +981,26 @@ p {
margin-bottom: 15px !important;
}
.mb-5 {
margin-bottom: 5px !important;
}
.mt-5 {
margin-bottom: 5px !important;
}
.mb-10 {
margin-bottom: 10px !important;
}
.mt-10 {
margin-bottom: 10px !important;
}
::marker {
display: none !important;
}
.graphic-post {
padding: 1rem 1rem;
text-align: start;
@ -968,6 +1013,18 @@ p {
align-items: center !important;
}
.graphic-post-column {
padding: 1rem 1rem;
text-align: start;
color: inherit !important;
text-decoration: none !important;
background-color: #222 !important;
border-radius: 0.25px;
display: flex;
flex-direction: column;
align-items: center !important;
}
.error-dialog {
padding: 5px;
margin-bottom: 10px;

View File

@ -31,6 +31,10 @@ Route::get('/fetch/categories', 'Controller@fetchCategories');
Route::post('/fetch/categories/post', 'Controller@fetchCategoriesFP');
Route::get('/fetch/categories/catalog', 'Controller@fetchCategoriesCatalog');
Route::get('/fetch/category/catalog/{id}', 'Controller@fetchCategoryCatalog');
Route::get('/fetch/category/{id}', 'Controller@fetchCategory');
Route::get('/fetch/posts/{id}', 'Controller@fetchPosts');