Skip to content

Commit

Permalink
Incremental architecture revision
Browse files Browse the repository at this point in the history
  • Loading branch information
sudoshi committed Jan 30, 2025
1 parent cd0ddd8 commit e00181a
Show file tree
Hide file tree
Showing 15 changed files with 3,228 additions and 47 deletions.
8 changes: 5 additions & 3 deletions bootstrap/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@

return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
web: __DIR__ . '/../routes/web.php',
commands: __DIR__ . '/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\App\Http\Middleware\HandleInertiaRequests::class,
\Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets::class,
]);
Expand All @@ -20,4 +21,5 @@
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
})
->create();
83 changes: 83 additions & 0 deletions config/sanctum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

use Laravel\Sanctum\Sanctum;

return [

/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort()
))),

/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/

'guard' => ['web'],

/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. This will override any values set in the token's
| "expires_at" attribute, but first-party sessions are not affected.
|
*/

'expiration' => null,

/*
|--------------------------------------------------------------------------
| Token Prefix
|--------------------------------------------------------------------------
|
| Sanctum can prefix new tokens in order to take advantage of numerous
| security scanning initiatives maintained by open source platforms
| that notify developers if they commit tokens into repositories.
|
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning
|
*/

'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),

/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/

'middleware' => [
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
],

];
16 changes: 11 additions & 5 deletions database/migrations/0001_01_01_000000_create_users_table.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
/**
* Run the migrations.
*/
public function up(): void
{
public function up(): void
{
if (!Schema::hasTable('prod.users')) {
Schema::create('prod.users', function (Blueprint $table) {
$table->id();
$table->string('name');
Expand All @@ -19,22 +20,27 @@ public function up(): void
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
});
}

if (!Schema::hasTable('prod.password_reset_tokens')) {
Schema::create('prod.password_reset_tokens', function (Blueprint $table) {
$table->string('email')->primary();
$table->string('token');
$table->timestamp('created_at')->nullable();
});
});
}

if (!Schema::hasTable('prod.sessions')) {
Schema::create('prod.sessions', function (Blueprint $table) {
$table->string('id')->primary();
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->longText('payload');
$table->integer('last_activity')->index();
});
});
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->morphs('tokenable');
$table->string('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamp('expires_at')->nullable();
$table->timestamps();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('personal_access_tokens');
}
};
54 changes: 30 additions & 24 deletions resources/js/Components/BlockSchedule/BlockScheduleManager.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import Modal from '../Modal';
import Form from './Form';
import Select from './Select';
import { Icon } from '@iconify/react';
import axios from 'axios';
import { usePage, router } from '@inertiajs/react';
import { usePage } from '@inertiajs/react';
import DataService from '../../services/data-service';

const BlockScheduleManager = () => {
const { auth } = usePage().props;
Expand All @@ -20,24 +20,24 @@ const BlockScheduleManager = () => {
const [services, setServices] = useState([]);
const [rooms, setRooms] = useState([]);
useEffect(() => {
if (!auth.user) {
router.visit('/login');
return;
}

const fetchData = async () => {
try {
const [blocksRes, utilizationRes, servicesRes, roomsRes] = await Promise.all([
axios.get('/api/blocks'),
axios.get('/api/blocks/utilization'),
axios.get('/api/services'),
axios.get('/api/rooms')
const [blocks, utilization, services] = await Promise.all([
DataService.getBlockTemplates(),
DataService.getBlockUtilization(selectedDate.toISOString().split('T')[0]),
DataService.getServices()
]);

setBlocks(blocksRes.data);
setUtilization(utilizationRes.data);
setServices(servicesRes.data);
setRooms(roomsRes.data);
setBlocks(blocks);
setUtilization(utilization);
setServices(services);
setRooms([
{ room_id: 1, name: 'OR-1' },
{ room_id: 2, name: 'OR-2' },
{ room_id: 3, name: 'OR-3' },
{ room_id: 4, name: 'OR-4' },
{ room_id: 5, name: 'OR-5' }
]);
setError(null);
} catch (err) {
console.error('Error fetching data:', err);
Expand All @@ -48,7 +48,7 @@ const BlockScheduleManager = () => {
};

fetchData();
}, []);
}, [selectedDate]);

const getBlocksForDate = (date) => {
return blocks.filter(block =>
Expand Down Expand Up @@ -80,13 +80,19 @@ const BlockScheduleManager = () => {
const handleSubmit = async (e) => {
e.preventDefault();
try {
await axios.post('/api/blocks', formData);
const [blocksRes, utilizationRes] = await Promise.all([
axios.get('/api/blocks'),
axios.get('/api/blocks/utilization')
]);
setBlocks(blocksRes.data);
setUtilization(utilizationRes.data);
// In mock mode, just update the local state with new block
const newBlock = {
block_id: blocks.length + 1,
room_id: formData.room_id,
service_id: formData.service_id,
service_name: services.find(s => s.service_id === formData.service_id)?.name,
block_date: formData.block_date,
start_time: formData.start_time,
end_time: formData.end_time,
title: `${services.find(s => s.service_id === formData.service_id)?.name} Block`
};

setBlocks([...blocks, newBlock]);
setShowModal(false);
setFormData({
service_id: '',
Expand Down
23 changes: 9 additions & 14 deletions resources/js/Components/Dashboard/DashboardOverview.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import Card from './Card';
import Stats from './Stats';
import { Icon } from '@iconify/react';
import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
import axios from 'axios';
import { usePage, router } from '@inertiajs/react';
import { usePage } from '@inertiajs/react';
import DataService from '../../services/data-service';

const DashboardOverview = () => {
const { auth } = usePage().props;
Expand All @@ -15,22 +15,17 @@ const DashboardOverview = () => {
const [error, setError] = useState(null);

useEffect(() => {
if (!auth.user) {
router.visit('/login');
return;
}

const fetchDashboardData = async () => {
try {
const [metricsRes, casesRes, roomsRes] = await Promise.all([
axios.get('/api/cases/metrics'),
axios.get('/api/cases/today'),
axios.get('/api/cases/room-status')
const [metrics, cases, rooms] = await Promise.all([
DataService.getDashboardMetrics(),
DataService.getTodaysCases(),
DataService.getRoomStatus()
]);

setMetrics(metricsRes.data);
setTodaysCases(casesRes.data);
setRoomStatus(roomsRes.data);
setMetrics(metrics);
setTodaysCases(cases);
setRoomStatus(rooms);
setError(null);
} catch (err) {
console.error('Error fetching dashboard data:', err);
Expand Down
7 changes: 6 additions & 1 deletion resources/js/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import './bootstrap';
import { createInertiaApp } from '@inertiajs/react';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { createRoot } from 'react-dom/client';
import { HeroUIProvider } from '@heroui/react';
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';

createInertiaApp({
Expand All @@ -15,7 +16,11 @@ createInertiaApp({
),
setup({ el, App, props }) {
const root = createRoot(el);
root.render(<App {...props} />);
root.render(
<HeroUIProvider>
<App {...props} />
</HeroUIProvider>
);
},
progress: {
color: '#4B5563',
Expand Down
Loading

0 comments on commit e00181a

Please sign in to comment.