vite cfg fix, floorplan

This commit is contained in:
t0is 2025-07-09 15:35:23 +02:00
parent 2b9391f5e9
commit f97b49cbdf
9 changed files with 181 additions and 56 deletions

View File

@ -72,13 +72,13 @@ class StockPositionController extends Controller
}
public function getPosition(Request $request)
public function getPosition(Request $request, int $id)
{
// 1) Eagerload the real relationships
$position = StockPosition::with([
'sections.entries.physicalItem',
'shelf.rack.line.room',
])->findOrFail(2);
])->findOrFail($id);
// 2) Compute the storage address string
$position->storage_address = $position->storageAddress();

View File

@ -22,6 +22,13 @@ class StockRackController extends Controller
return response()->json($rack, 201);
}
public function show(Request $request, int $id)
{
$rack = StockRack::with(['line', 'shelves.positions.sections'])->findOrFail($id);
return response()->json($rack, 201);
}
public function update(Request $request, StockRack $rack)
{
$data = $request->validate([

View File

@ -3,7 +3,8 @@
"type": "module",
"scripts": {
"build": "vite build",
"dev": "vite"
"dev": "vite",
"dev:android": "EMULATOR=1 vite --host 0.0.0.0"
},
"devDependencies": {
"@capacitor/cli": "^7.4.1",

View File

@ -1,40 +1,56 @@
// components/RackDetails.tsx
import React from 'react';
import {StockRack} from '@/types';
import {StockRack, StockPosition} from '@/types';
interface RackDetailsProps {
rack: StockRack | null;
onPositionClick: (posId: number) => void;
}
export default function RackModalDetails({ rack }: RackDetailsProps) {
export default function RackModalDetails({rack, onPositionClick}: RackDetailsProps) {
return (
<div className="overflow-auto p-4">
<div className="flex flex-col space-y-4">
{rack.shelves?.map((shelf) => (
<div key={shelf.shelf_symbol} className="flex items-start space-x-4">
<div key={shelf.shelf_symbol} className="flex items-start space-x-4 flex-col">
{/* Shelf label */}
<div className="font-bold">Shelf {shelf.shelf_symbol}</div>
{/* Positions container */}
<div className="flex space-x-4">
{shelf.positions.map((position) => (
<div key={position.position_symbol} className="border rounded-lg p-3">
<div className="flex space-x-4 border border-white dark:border-gray-700 h-max min-h-40 w-full">
{shelf.positions.length > 0 ? (
shelf.positions.map((position) => (
<div
key={position.position_symbol}
className="border rounded-lg p-3 w-full cursor-pointer"
onClick={() => onPositionClick(position.position_id)}
>
{/* Position label */}
<div className="font-semibold mb-2">Pos {position.position_symbol}</div>
{/* Sections grid */}
<div className="grid grid-cols-3 gap-2">
<div className="grid grid-cols-1 gap-2">
{position.sections.map((section) => (
<div
key={section.section_symbol}
className="border rounded p-1 text-sm text-center"
className="border rounded p-1 text-center bg-primary font-bold cursor-pointer"
onClick={(e) => {
e.stopPropagation();
onPositionClick(position.position_id);
}}
>
{section.section_symbol}
Sec {section.section_symbol}
</div>
))}
</div>
</div>
))}
))
) : (
<div className="border rounded-lg p-3 w-full flex items-center justify-center">No
positions</div>
)}
</div>
</div>
))}

View File

@ -6,7 +6,7 @@ import { StockPosition, StockSection } from "@/types"
interface Props {
onClose: () => void
selectedPosition: () => StockPosition
selectedPosition: StockPosition
}
interface EditableSection {

View File

@ -90,6 +90,12 @@ export default function AppLayout({
>
PDA
</NavLink>
<NavLink
href={route('floorPlan')}
active={route().current('floorPlan')}
>
Floor plan
</NavLink>
</div>
</div>
@ -323,6 +329,13 @@ export default function AppLayout({
>
PDA
</ResponsiveNavLink>
<ResponsiveNavLink
href={route('floorPlan')}
active={route().current('floorPlan')}
>
Floor plan
</ResponsiveNavLink>
</div>
{/* <!-- Responsive Settings Options --> */}

View File

@ -3,12 +3,41 @@ import AppLayout from '@/Layouts/AppLayout';
import { Stage, Layer, Rect, Image as KonvaImage, Text, Transformer } from 'react-konva';
import useImage from 'use-image';
import axios from 'axios';
import {StockRoom, LayoutItem, LayoutLine, StockRack, StockLine} from '@/types';
import {StockRoom, LayoutItem, LayoutLine, StockRack, StockLine, StockPosition} from '@/types';
import RackModalDetails from "@/Components/RackModalDetails";
import EditStockSections from '@/Components/modals/EditStockSections';
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
export default function FloorPlan() {
// at the top of FloorPlan()
const [showEditSectionsModal, setShowEditSectionsModal] = useState(false);
const [selectedPositionForEditing, setSelectedPositionForEditing] = useState<StockPosition | null>(null);
// fire this when RackModalDetails tells us “user clicked a position”
const handleOpenSections = async (posId: number) => {
try {
console.log(posId);
// 1⃣ pull down the fresh position (with capacity & sections)
const { data: freshPos } = await axios.get<StockPosition>(
`/api/stockPositions/${posId}`,
{ withCredentials: true }
);
// 2⃣ stash it & open the modal
setSelectedPositionForEditing(freshPos);
setShowEditSectionsModal(true);
} catch (err) {
console.error(err);
alert('Could not load position details. Please try again.');
}
};
// pass this into EditStockSections so that onClose we go back to RackModalDetails
const handleCloseSections = () => {
setShowEditSectionsModal(false);
};
// Rooms & selected room
const [rooms, setRooms] = useState<StockRoom[]>([]);
const [selectedRoom, setSelectedRoom] = useState<StockRoom | null>(null);
@ -55,6 +84,27 @@ export default function FloorPlan() {
.catch(console.error);
}, []);
useEffect(() => {
if (!showEditSectionsModal && selectedRoom) {
loadLayout(selectedRoom.room_id);
}
}, [showEditSectionsModal, selectedRoom]);
useEffect(() => {
if (!showEditSectionsModal && editModal.visible && editModal.type === 'rack' && editModal.item_obj) {
// grab the just-saved rack by its ID:
axios.get<StockRack>(`/api/stock-racks/${(editModal.item_obj as StockRack).rack_id}`, {
withCredentials: true
})
.then(({ data: freshRack }) => {
setEditModal(m => ({ ...m, item_obj: freshRack }));
})
.catch(err => {
console.error('Could not refresh rack details:', err);
});
}
}, [showEditSectionsModal, editModal.visible]);
// Load a room's layout (or show create modal)
const loadLayout = async (roomId: number) => {
try {
@ -451,7 +501,7 @@ export default function FloorPlan() {
{/* Edit Modal */}
{editModal.visible && (
<div className="modal modal-open">
<div className="modal-box">
<div className="modal-box max-w-[50%]">
<h3 className="font-bold text-lg">Edit {editModal.type}</h3>
<input
type="text"
@ -470,7 +520,7 @@ export default function FloorPlan() {
{editModal.type === 'rack' && (
<div className="mt-4">
<h4 className="font-bold mb-2">Shelves &amp; Sections</h4>
<RackModalDetails rack={editModal.item_obj} />
<RackModalDetails rack={editModal.item_obj} onPositionClick={handleOpenSections} />
</div>
)}
<div className="modal-action">
@ -482,6 +532,18 @@ export default function FloorPlan() {
</div>
)}
{/* === Sections Editor Nested Modal === */}
{showEditSectionsModal && selectedPositionForEditing && (
<div className="modal modal-open">
<div className="modal-box max-w-[50%]">
<EditStockSections
selectedPosition={selectedPositionForEditing}
onClose={handleCloseSections}
/>
</div>
</div>
)}
{/* Create Layout Modal */}
{showCreateModal && (
<div className="modal modal-open">

View File

@ -126,13 +126,14 @@ Route::get('/stockStatusList', [StockEntryController::class, 'getStatusList']);
Route::get('/pdaView/getStockPosition', [StockPositionController::class, 'getPosition']);
Route::get('/pdaView/getStockPosition/{id}', [StockPositionController::class, 'getPosition']);
Route::post('/pdaView/moveStockSection', [StockSectionController::class, 'movePosition']);
Route::post('/pdaView/changeCount', [StockSectionController::class, 'changeCount']);
Route::put('/stockPositions/{id}', [StockPositionController::class, 'update']);
Route::get('/stockPositions/{id}', [StockPositionController::class, 'getPosition']);
Route::get('/stockSections/{id}', [StockSectionController::class, 'getSection']);
Route::post('/stockSections', [StockSectionController::class, 'store']);
Route::put('/stockSections/{id}', [StockSectionController::class, 'update']);
@ -153,6 +154,7 @@ Route::get('/stockStatusList', [StockEntryController::class, 'getStatusList']);
Route::delete ('/stock-lines/{line}', [StockLineController::class, 'destroy']);
// Racks
Route::get ('/stock-racks/{rack}', [StockRackController::class, 'show']);
Route::post ('/stock-racks', [StockRackController::class, 'store']);
Route::put ('/stock-racks/{rack}', [StockRackController::class, 'update']);
Route::delete ('/stock-racks/{rack}', [StockRackController::class, 'destroy']);

View File

@ -1,8 +1,18 @@
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';
// vite.config.ts
import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import react from '@vitejs/plugin-react'
export default defineConfig(({ command }) => {
const isDev = command === 'serve'
const isBuild = command === 'build'
// set EMULATOR=1 in your npm script when you want to work on the Android build
const isEmulator = !!process.env.EMULATOR
return {
// for webdev we load from “/”, for the Capacitor build we need “./”
base: isBuild ? './' : '/',
export default defineConfig({
plugins: [
laravel({
input: 'resources/js/app.tsx',
@ -10,21 +20,35 @@ export default defineConfig({
}),
react(),
],
base: './',
resolve: { alias: { '@': '/resources/js' } },
resolve: {
alias: {
'@': '/resources/js',
},
},
// only spin up a dev server when running `vite` or `npm run dev`
...(isDev && {
server: {
// if you do `--host`, Vite will override this to 0.0.0.0
host: isEmulator ? '0.0.0.0' : 'localhost',
port: 5173,
strictPort: true,
cors: true,
hmr: {
// emulator needs 10.0.2.2, browser just localhost
host: isEmulator ? '10.0.2.2' : 'localhost',
port: 5173,
},
},
}),
// only emit your Capacitor build when running `vite build` or `npm run build`
...(isBuild && {
build: {
outDir: 'public/spa',
emptyOutDir: true,
},
server: {
host: '0.0.0.0',
port: 5173,
strictPort: true,
// Allow crossorigin requests from your Laravel app:
cors: true,
hmr: {
host: '10.0.2.2',
port: 5173,
},
},
});
}),
}
})