Skip to content

Commit

Permalink
added admin status page
Browse files Browse the repository at this point in the history
  • Loading branch information
tareq1988 committed Jan 17, 2024
1 parent 13f99f6 commit 01447d0
Show file tree
Hide file tree
Showing 20 changed files with 960 additions and 66 deletions.
14 changes: 14 additions & 0 deletions app/Http/Controllers/Admin/DashboardController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class DashboardController extends Controller
{
public function index()
{
return inertia('Admin/Dashboard');
}
}
14 changes: 14 additions & 0 deletions app/Http/Controllers/Admin/SettingsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class SettingsController extends Controller
{
public function index()
{
return inertia('Admin/Settings');
}
}
71 changes: 71 additions & 0 deletions app/Http/Controllers/Admin/StatusController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace App\Http\Controllers\Admin;

use App\Models\Status;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Validation\ValidationException;

class StatusController extends Controller
{
public function index()
{
$statuses = Status::orderBy('order')->get();

return inertia('Admin/Status', [
'statuses' => $statuses
]);
}

public function store(Request $request)
{
$request->validate([
'name' => 'required|string|unique:statuses,name',
'color' => 'required|string',
]);

Status::create([
'name' => $request->name,
'color' => $request->color,
'order' => Status::count() + 1,
]);

return redirect()->back()->with('success', 'Status created.');
}

public function update(Request $request)
{
$request->validate([
'statuses' => 'required|array',
'statuses.*.id' => 'required|integer|exists:statuses,id',
'statuses.*.name' => 'required|string',
'statuses.*.color' => 'required|string',
'statuses.*.in_roadmap' => 'required|boolean',
'deleted' => 'nullable|array',
'deleted.*' => 'required|integer|exists:statuses,id',
]);

$inRoadmapCount = collect($request->statuses)->filter(function ($status) {
return $status['in_roadmap'] === true;
})->count();

if ($inRoadmapCount > 3) {
throw ValidationException::withMessages([
'statuses' => 'Only 3 statuses can be in the roadmap at a time.',
]);
}

foreach ($request->statuses as $status) {
Status::find($status['id'])->update([
'name' => $status['name'],
'color' => $status['color'],
'in_roadmap' => $status['in_roadmap'],
]);
}

Status::destroy($request->deleted);

return redirect()->back()->with('success', 'Statuses updated.');
}
}
2 changes: 1 addition & 1 deletion app/Http/Controllers/Frontend/HomeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function index()
->orderBy('order')
->get();
$statuses = Status::select('id', 'name', 'color')
->whereIn('id', [2, 3, 4])
->inRoadmap()
->get();

$posts = Post::whereIn('status_id', $statuses->pluck('id'))
Expand Down
1 change: 0 additions & 1 deletion app/Http/Controllers/Frontend/PostController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ class PostController extends Controller
{
public function show(Board $board, $post)
{

$post = Post::where('slug', $post)->withVote()->firstOrFail();
$post->load('creator');

Expand Down
2 changes: 2 additions & 0 deletions app/Http/Middleware/HandleInertiaRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public function share(Request $request): array
],
'appName' => config('app.name'),
'appLogo' => config('app.logo'),
'success' => fn () => $request->session()->get('success'),
'error' => fn () => $request->session()->get('error'),
];
}
}
9 changes: 7 additions & 2 deletions app/Models/Status.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ class Status extends Model
{
use HasFactory;

protected $fillable = ['name', 'color'];

protected $fillable = ['name', 'color', 'in_roadmap', 'order'];
protected $casts = ['in_roadmap' => 'boolean'];
protected $hidden = ['created_at', 'updated_at'];

public function posts()
Expand All @@ -22,4 +22,9 @@ public function post()
{
return $this->belongsTo(Post::class);
}

public function scopeInRoadmap($query)
{
return $query->where('in_roadmap', 1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public function up(): void
$table->id();
$table->string('name');
$table->string('color');
$table->tinyInteger('order')->default(0);
$table->boolean('in_roadmap')->default(false);
$table->timestamps();
});
}
Expand Down
17 changes: 8 additions & 9 deletions database/seeders/DatabaseSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,17 @@ class DatabaseSeeder extends Seeder
*/
public function run(): void
{
// User::factory(10)->create();
\App\Models\User::factory()->create([
'name' => 'Admin User',
'email' => '[email protected]',
'password' => bcrypt('password'),
'role' => 'admin',
]);

$this->call([
// StatusSeeder::class,
// BoardSeeder::class,
StatusSeeder::class,
BoardSeeder::class,
PostSeeder::class,
]);


// \App\Models\User::factory()->create([
// 'name' => 'Test User',
// 'email' => '[email protected]',
// ]);
}
}
11 changes: 5 additions & 6 deletions database/seeders/StatusSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,17 @@ class StatusSeeder extends Seeder
public function run(): void
{
$statuses = [
['name' => 'Under Review', 'color' => '#85b5b5'],
['name' => 'Planned', 'color' => '#1fa0ff'],
['name' => 'In Progress', 'color' => '#c17aff'],
['name' => 'Complete', 'color' => '#6cd345'],
['name' => 'Closed', 'color' => '#ed2b2b'],
['name' => 'Under Review', 'color' => '#85b5b5', 'order' => 0],
['name' => 'Planned', 'color' => '#1fa0ff', 'order' => 1, 'in_roadmap' => true],
['name' => 'In Progress', 'color' => '#c17aff', 'order' => 2, 'in_roadmap' => true],
['name' => 'Complete', 'color' => '#6cd345', 'order' => 3, 'in_roadmap' => true],
['name' => 'Closed', 'color' => '#ed2b2b', 'order' => 4, 'in_roadmap' => false],
];

foreach ($statuses as $status) {
try {
Status::create($status);
} catch (\Throwable $th) {

}
}
}
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@tailwindcss/forms": "^0.5.3",
"@types/node": "^18.13.0",
"@types/react": "^18.0.28",
"@types/react-color": "^3.0.11",
"@types/react-dom": "^18.0.10",
"@vitejs/plugin-react": "^4.2.0",
"autoprefixer": "^10.4.12",
Expand All @@ -25,7 +26,9 @@
},
"dependencies": {
"@heroicons/react": "^2.1.1",
"@radix-ui/react-popover": "^1.0.7",
"@wedevs/tail-react": "^0.3.3",
"classnames": "^2.5.1"
"classnames": "^2.5.1",
"react-color": "^2.19.3"
}
}
}
38 changes: 29 additions & 9 deletions resources/js/Layouts/AuthenticatedLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { useState, PropsWithChildren, ReactNode } from 'react';
import { useEffect, useState, PropsWithChildren, ReactNode } from 'react';
import Dropdown from '@/Components/Dropdown';
import NavLink from '@/Components/NavLink';
import ResponsiveNavLink from '@/Components/ResponsiveNavLink';
import { Link, usePage } from '@inertiajs/react';
import { PageProps, User } from '@/types';
import { ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline';
import { Notice } from '@wedevs/tail-react';

export default function Authenticated({
user,
header,
children,
}: PropsWithChildren<{ user: User; header?: ReactNode }>) {
}: PropsWithChildren<{ header?: ReactNode }>) {
const [showingNavigationDropdown, setShowingNavigationDropdown] =
useState(false);

const { appName, appLogo } = usePage<PageProps>().props;
const { auth, appName, appLogo, success, error } = usePage<PageProps>().props;

return (
<div className="min-h-screen bg-gray-100 dark:bg-gray-900">
Expand All @@ -40,14 +40,21 @@ export default function Authenticated({
>
Dashboard
</NavLink>

<NavLink
href={route('admin.statuses.index')}
active={route().current('admin.statuses.index')}
>
Status
</NavLink>
</div>
</div>

<div className="hidden sm:flex sm:items-center sm:ms-6">
<a
href={route('home')}
target="_blank"
className="text-sm inline-flex text-gray-600"
className="text-sm font-medium inline-flex text-gray-500 hover:text-gray-700"
>
<span>Preview</span>
<ArrowTopRightOnSquareIcon className="h-5 w-5 ml-2" />
Expand All @@ -61,7 +68,7 @@ export default function Authenticated({
type="button"
className="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-300 focus:outline-none transition ease-in-out duration-150"
>
{user.name}
{auth.user.name}

<svg
className="ms-2 -me-0.5 h-4 w-4"
Expand Down Expand Up @@ -151,10 +158,10 @@ export default function Authenticated({
<div className="pt-4 pb-1 border-t border-gray-200 dark:border-gray-600">
<div className="px-4">
<div className="font-medium text-base text-gray-800 dark:text-gray-200">
{user.name}
{auth.user.name}
</div>
<div className="font-medium text-sm text-gray-500">
{user.email}
{auth.user.email}
</div>
</div>

Expand Down Expand Up @@ -182,7 +189,20 @@ export default function Authenticated({
</header>
)}

<main>{children}</main>
<main className="max-w-7xl mx-auto sm:px-6 lg:px-8 py-12 ">
{error && (
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<Notice type="error" label={error} className="mb-4" />
</div>
)}

{success && (
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<Notice type="success" label={success} className="mb-4" />
</div>
)}
{children}
</main>
</div>
);
}
30 changes: 30 additions & 0 deletions resources/js/Pages/Admin/Dashboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
import { Head } from '@inertiajs/react';
import { PageProps } from '@/types';

const Dashboard = ({ auth }: PageProps) => {
return (
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<Head title="Dashboard" />

<div className="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 text-gray-900 dark:text-gray-100">
You're logged in!
</div>
</div>
</div>
);
};

Dashboard.layout = (page: React.ReactNode) => (
<AuthenticatedLayout
children={page}
header={
<h2 className="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
Dashboard
</h2>
}
></AuthenticatedLayout>
);

export default Dashboard;
Loading

0 comments on commit 01447d0

Please sign in to comment.