updateeeeee

This commit is contained in:
lubiana 2025-06-10 20:14:19 +02:00
parent 0c758749e0
commit ca9819a436
Signed by: lubiana
SSH key fingerprint: SHA256:vW1EA0fRR3Fw+dD/sM0K+x3Il2gSry6YRYHqOeQwrfk
12 changed files with 214 additions and 156 deletions

View file

@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration;
/** /**
* Auto-generated Migration: Please modify to your needs! * Auto-generated Migration: Please modify to your needs!
*/ */
final class Version20250609175837 extends AbstractMigration final class Version20250610173233 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
{ {
@ -23,20 +23,11 @@ final class Version20250609175837 extends AbstractMigration
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
CREATE TABLE drink_type (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable) CREATE TABLE drink_type (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
, updated_at DATETIME NOT NULL --(DC2Type:datetime_immutable) , updated_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
, name VARCHAR(255) NOT NULL, description CLOB DEFAULT NULL, desired_stock INTEGER NOT NULL) , name VARCHAR(255) NOT NULL, description CLOB DEFAULT NULL, wanted_stock INTEGER NOT NULL, current_stock INTEGER NOT NULL)
SQL); SQL);
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
CREATE UNIQUE INDEX UNIQ_841484B15E237E06 ON drink_type (name) CREATE UNIQUE INDEX UNIQ_841484B15E237E06 ON drink_type (name)
SQL); SQL);
$this->addSql(<<<'SQL'
CREATE TABLE inventory_record (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, drink_type_id INTEGER NOT NULL, quantity INTEGER NOT NULL, timestamp DATETIME NOT NULL --(DC2Type:datetime_immutable)
, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
, updated_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
, CONSTRAINT FK_9BE8033AE7E8D8A1 FOREIGN KEY (drink_type_id) REFERENCES drink_type (id) NOT DEFERRABLE INITIALLY IMMEDIATE)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_9BE8033AE7E8D8A1 ON inventory_record (drink_type_id)
SQL);
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
CREATE TABLE "order" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable) CREATE TABLE "order" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
, updated_at DATETIME NOT NULL --(DC2Type:datetime_immutable) , updated_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
@ -73,9 +64,6 @@ final class Version20250609175837 extends AbstractMigration
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
DROP TABLE drink_type DROP TABLE drink_type
SQL); SQL);
$this->addSql(<<<'SQL'
DROP TABLE inventory_record
SQL);
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
DROP TABLE "order" DROP TABLE "order"
SQL); SQL);

File diff suppressed because one or more lines are too long

View file

@ -29,45 +29,145 @@
} }
} }
/* Light Mode (Default) */ /*
* =================================================================================================
* 💅 GAY, SLAY & FABULOUS THEME 💅
*
* A Bootstrap override that's unapologetically queer, vibrant, and readable.
* Because your website deserves to be as iconic as you are.
*
* Designed with love, glitter, and a whole lot of sass.
* =================================================================================================
*/
:root { :root {
--bs-primary: #ff47a3; /* Hot Pink */ /* 🌈✨ The Main Attraction: A Vibrant & Proud Palette ✨🌈 */
--bs-secondary: #7367f0; /* Lavender */ --bs-red: #FF3860; /* 🍒 Cherry Pop Realness */
--bs-success: #53e69d; /* Minty Green */ --bs-orange: #FF9F43; /* 🍊 Tangerine Dream Queen */
--bs-info: #51caff; /* Sky Blue */ --bs-yellow: #FFE156; /* 🌟 Superstar Spotlight */
--bs-warning: #ffd53e; /* Sunshine Yellow */ --bs-green: #34C759; /* 🌿 Growth & chosen family */
--bs-danger: #ff5666; /* Coral Red */ --bs-teal: #20c997; /* 🧜‍♀️ Mermaid's Grotto */
--bs-light: #fff7fa; /* Almost-white Pink */ --bs-cyan: #4ED6FF; /* 🧊 Iced Genderfluid */
--bs-dark: #3b233d; /* Deep Purple */ --bs-blue: #5AC8FA; /* 🦋 Blue Bi You */
--bs-indigo: #6C63FF; /* 🦄 Unicorn Energy */
--bs-purple: #AF52DE; /* 💜 Violets for Visibility */
--bs-pink: #FF6F91; /* 💖 Queerberry Kiss */
/* Quirk it up further */ /* 💅 Neutrals That Are Anything But Neutral 💅 */
--bs-body-bg: #fff7fa; --bs-black: #1A202C; /* 🕶️ Midnight Manifesto */
--bs-body-color: #3b233d; --bs-white: #F8F7FF; /* ☁️ Cloud Nine Comfort */
--bs-link-color: #ff47a3; --bs-gray: #A0AEC0; /* 🌫️ Foggy Festival Morning */
--bs-link-hover-color: #7367f0; --bs-gray-dark: #2D3748; /* 🖤 Emo Afterparty */
--bs-border-color: #ffb8e1; --bs-gray-100: #F7FAFC;
--bs-gray-200: #EDF2F7;
--bs-gray-300: #E2E8F0;
--bs-gray-400: #CBD5E1;
--bs-gray-500: #A0AEC0;
--bs-gray-600: #718096;
--bs-gray-700: #4A5568;
--bs-gray-800: #2D3748;
--bs-gray-900: #1A202C;
/* 💖 Semantic Roles: Give Every Color a Job 💖 */
--bs-primary: var(--bs-indigo); /* Main Character Energy */
--bs-secondary: var(--bs-pink); /* Sassy Sidekick */
--bs-success: var(--bs-green); /* Yas, Queen! (Success) */
--bs-info: var(--bs-cyan); /* The Tea (Information) */
--bs-warning: var(--bs-orange); /* Hun, Be Careful (Warning) */
--bs-danger: var(--bs-red); /* Not Today, Satan (Danger) */
--bs-light: var(--bs-gray-100); /* Daytime Disco */
--bs-dark: var(--bs-gray-900); /* Velvet Rope */
/* 📖 Fonts with Personality 📖 */
/* Recommendation: Import "Quicksand" and "Fira Mono" from Google Fonts for the full effect! */
--bs-font-sans-serif: "Quicksand", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: "Fira Mono", SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
/* ✨ The Gradient That Slays ✨ */
--bs-gradient: linear-gradient(93deg, var(--bs-indigo), var(--bs-pink) 50%, var(--bs-orange));
/* 🎨 Core Styles for a Flawless Look 🎨 */
--bs-body-color: var(--bs-gray-800);
--bs-body-bg: var(--bs-white);
--bs-emphasis-color: var(--bs-black);
--bs-secondary-color: rgba(45, 55, 72, 0.75);
--bs-secondary-bg: var(--bs-gray-200);
--bs-tertiary-color: rgba(45, 55, 72, 0.5);
--bs-tertiary-bg: var(--bs-gray-100);
--bs-heading-color: inherit;
--bs-link-color: var(--bs-primary);
--bs-link-hover-color: var(--bs-purple);
--bs-code-color: var(--bs-pink);
--bs-highlight-bg: #fff9c4; /* A soft, buttery highlight */
--bs-border-color: var(--bs-gray-300);
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
--bs-border-radius: 0.5rem; /* A little softer, a little friendlier */
--bs-border-radius-lg: 0.75rem;
--bs-border-radius-sm: 0.25rem;
--bs-box-shadow: 0 0.25rem 1.5rem rgba(45, 55, 72, 0.1);
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(45, 55, 72, 0.07);
--bs-box-shadow-lg: 0 1rem 3rem rgba(45, 55, 72, 0.15);
} }
/* Dark Mode (Bootstrap's preferred way) */ /*
@media (prefers-color-scheme: dark) { * =================================================================================================
:root { * 🌙 DARK MODE: VOGUE AFTER MIDNIGHT 🌙
--bs-primary: #ff9cd7; /* Pastel Pink */ *
--bs-secondary: #b39afd; /* Light Lavender */ * Because fabulousness doesn't sleep. This is for the night owls, the dreamers,
--bs-success: #8fffd9; /* Lighter Mint */ * and everyone who knows the party really starts after dark.
--bs-info: #90e7ff; /* Pastel Sky Blue */ * =================================================================================================
--bs-warning: #fff4b1; /* Pale Yellow */ */
--bs-danger: #ffb1b8; /* Soft Coral */
--bs-light: #2a102d; /* Deep Purple-Black */
--bs-dark: #fff7fa; /* Reverse for dark backgrounds */
--bs-body-bg: #2a102d; [data-bs-theme=dark] {
--bs-body-color: #fff7fa; color-scheme: dark;
--bs-link-color: #ff9cd7;
--bs-link-hover-color: #b39afd; /* 💅 Dark Mode Neutrals: Still Chic 💅 */
--bs-border-color: #6e3a6e; --bs-body-color: var(--bs-gray-300);
} --bs-body-bg: var(--bs-gray-900);
--bs-emphasis-color: var(--bs-white);
--bs-secondary-color: rgba(237, 242, 247, 0.75);
--bs-secondary-bg: var(--bs-gray-800);
--bs-tertiary-color: rgba(237, 242, 247, 0.5);
--bs-tertiary-bg: #222938; /* A slightly bluer dark gray */
/* 💖 Semantic Roles: Nightlife Edition 💖 */
/* We use the same vibrant colors but adjust text emphasis and backgrounds for contrast */
--bs-primary-text-emphasis: #A3A0FF;
--bs-secondary-text-emphasis: #FFA8B9;
--bs-success-text-emphasis: #79F3B3;
--bs-info-text-emphasis: #99E5FF;
--bs-warning-text-emphasis: #FFC98B;
--bs-danger-text-emphasis: #FF7B96;
--bs-light-text-emphasis: #F7FAFC;
--bs-dark-text-emphasis: #E2E8F0;
--bs-primary-bg-subtle: #2A2859;
--bs-secondary-bg-subtle: #592432;
--bs-success-bg-subtle: #144A29;
--bs-info-bg-subtle: #194A59;
--bs-warning-bg-subtle: #593918;
--bs-danger-bg-subtle: #591422;
--bs-light-bg-subtle: var(--bs-gray-800);
--bs-dark-bg-subtle: var(--bs-gray-900);
--bs-primary-border-subtle: #4D49A6;
--bs-secondary-border-subtle: #A6435C;
--bs-success-border-subtle: #248047;
--bs-info-border-subtle: #2D8DA6;
--bs-warning-border-subtle: #A66629;
--bs-danger-border-subtle: #A6273D;
--bs-light-border-subtle: var(--bs-gray-700);
--bs-dark-border-subtle: var(--bs-gray-800);
/* 🎨 Core Styles for the Afterparty 🎨 */
--bs-heading-color: inherit;
--bs-link-color: var(--bs-blue);
--bs-link-hover-color: var(--bs-cyan);
--bs-code-color: var(--bs-secondary);
--bs-highlight-bg: #403d07;
--bs-border-color: var(--bs-gray-700);
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
} }
/* Top Navigation Bar Styles */ /* Top Navigation Bar Styles */
main { main {
margin-top: 20px; margin-top: 20px;

File diff suppressed because one or more lines are too long

View file

@ -6,7 +6,11 @@ namespace App\Controller;
use App\Entity\DrinkType; use App\Entity\DrinkType;
use App\Form\DrinkTypeForm; use App\Form\DrinkTypeForm;
use App\Form\DrinkTypeFormCurrentStockForm;
use App\Repository\DrinkTypeRepository;
use App\Repository\PropertyChangeLogRepository; use App\Repository\PropertyChangeLogRepository;
use App\Service\DrinkType\GetStockHistory;
use App\Service\DrinkType\GetWantedHistory;
use App\Service\InventoryService; use App\Service\InventoryService;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -18,10 +22,10 @@ use Symfony\Component\Routing\Attribute\Route;
final class DrinkTypeController extends AbstractController final class DrinkTypeController extends AbstractController
{ {
#[Route(name: 'app_drink_type_index', methods: ['GET'])] #[Route(name: 'app_drink_type_index', methods: ['GET'])]
public function index(InventoryService $inventoryService): Response public function index(DrinkTypeRepository $drinkTypeRepository): Response
{ {
return $this->render('drink_type/index.html.twig', [ return $this->render('drink_type/index.html.twig', [
'drink_stocks' => $inventoryService->getAllDrinkTypesWithStockLevels(true), 'drink_types' => $drinkTypeRepository->findAll(),
]); ]);
} }
@ -46,28 +50,20 @@ final class DrinkTypeController extends AbstractController
} }
#[Route(path: '/{id}', name: 'app_drink_type_show', methods: ['GET'])] #[Route(path: '/{id}', name: 'app_drink_type_show', methods: ['GET'])]
public function show(DrinkType $drinkType, PropertyChangeLogRepository $propertyChangeLogRepository): Response public function show(
DrinkType $drinkType,
GetStockHistory $getStockHistory,
GetWantedHistory $getWantedHistory,
): Response
{ {
// Get orders that contain this drink type // Get orders that contain this drink type
$orderItems = $drinkType->getOrderItems(); $orderItems = $drinkType->getOrderItems();
// Get inventory history for this drink type
$inventoryRecords = $drinkType->getInventoryRecords();
// Get desired stock history from PropertyChangeLog
$desiredStockHistory = $propertyChangeLogRepository->findBy([
'entityClass' => DrinkType::class,
'propertyName' => 'desiredStock',
'entityId' => $drinkType->getId(),
], [
'changeDate' => 'DESC',
]);
return $this->render('drink_type/show.html.twig', [ return $this->render('drink_type/show.html.twig', [
'drink_type' => $drinkType, 'drink_type' => $drinkType,
'order_items' => $orderItems, 'order_items' => $orderItems,
'inventory_records' => $inventoryRecords, 'stock_history' => $getStockHistory($drinkType),
'desired_stock_history' => $desiredStockHistory, 'wanted_history' => $getWantedHistory($drinkType),
]); ]);
} }
@ -89,6 +85,24 @@ final class DrinkTypeController extends AbstractController
]); ]);
} }
#[Route(path: '/{id}/update-stock', name: 'app_drink_type_update_stock', methods: ['GET', 'POST'])]
public function updateStock(Request $request, DrinkType $drinkType, EntityManagerInterface $entityManager): Response
{
$form = $this->createForm(DrinkTypeFormCurrentStockForm::class, $drinkType);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->flush();
return $this->redirectToRoute('app_index', [], Response::HTTP_SEE_OTHER);
}
return $this->render('drink_type/edit.html.twig', [
'drink_type' => $drinkType,
'form' => $form,
]);
}
#[Route(path: '/{id}', name: 'app_drink_type_delete', methods: ['POST'])] #[Route(path: '/{id}', name: 'app_drink_type_delete', methods: ['POST'])]
public function delete(Request $request, DrinkType $drinkType, EntityManagerInterface $entityManager): Response public function delete(Request $request, DrinkType $drinkType, EntityManagerInterface $entityManager): Response
{ {

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Controller; namespace App\Controller;
use App\Repository\DrinkTypeRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Attribute\Route;
@ -11,8 +12,11 @@ use Symfony\Component\Routing\Attribute\Route;
#[Route(path: '/', name: 'app_index')] #[Route(path: '/', name: 'app_index')]
final class Index extends AbstractController final class Index extends AbstractController
{ {
public function __invoke(): Response public function __invoke(DrinkTypeRepository $drinkTypeRepository): Response
{ {
return new Response('<h1>Hello World!</h1>'); return $this->render('index.html.twig', [
'drinkTypes' => $drinkTypeRepository->findWanted(),
]);
} }
} }

View file

@ -14,7 +14,11 @@ class DrinkTypeForm extends AbstractType
{ {
public function buildForm(FormBuilderInterface $builder, array $options): void public function buildForm(FormBuilderInterface $builder, array $options): void
{ {
$builder->add('name')->add('description')->add('desiredStock', NumberType::class); $builder
->add('name')
->add('description')
->add('currentStock', NumberType::class)
->add('wantedStock', NumberType::class);
} }
public function configureOptions(OptionsResolver $resolver): void public function configureOptions(OptionsResolver $resolver): void

View file

@ -5,34 +5,23 @@ declare(strict_types=1);
namespace App\Form; namespace App\Form;
use App\Entity\DrinkType; use App\Entity\DrinkType;
use App\Entity\InventoryRecord;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType; use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
class InventoryRecordForm extends AbstractType class DrinkTypeFormCurrentStockForm extends AbstractType
{ {
public function buildForm(FormBuilderInterface $builder, array $options): void public function buildForm(FormBuilderInterface $builder, array $options): void
{ {
$builder $builder
->add('quantity', NumberType::class) ->add('currentStock', NumberType::class);
->add('drinkType', EntityType::class, [
'class' => DrinkType::class,
'choice_label' => 'id',
'attr' => [
'style' => 'display: none;',
],
'label' => false,
])
;
} }
public function configureOptions(OptionsResolver $resolver): void public function configureOptions(OptionsResolver $resolver): void
{ {
$resolver->setDefaults([ $resolver->setDefaults([
'data_class' => InventoryRecord::class, 'data_class' => DrinkType::class,
]); ]);
} }
} }

View file

@ -10,19 +10,18 @@
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Description</th> <th>Description</th>
<th>DesiredStock</th> <th>Wanted Stock</th>
<th>DrinkStock</th> <th>Current Stock</th>
<th>actions</th> <th>actions</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for drink_stock in drink_stocks %} {% for drink_type in drink_types %}
{% set drink_type = drink_stock.record.drinkType %}
<tr> <tr>
<td>{{ drink_type.name }}</td> <td>{{ drink_type.name }}</td>
<td>{{ drink_type.description }}</td> <td>{{ drink_type.description }}</td>
<td>{{ drink_type.desiredStock }}</td> <td>{{ drink_type.wantedStock }}</td>
<td>{{ drink_stock.record.quantity }}</td> <td>{{ drink_type.currentStock }}</td>
<td> <td>
<a href="{{ path('app_drink_type_show', {'id': drink_type.id}) }}">show</a> <a href="{{ path('app_drink_type_show', {'id': drink_type.id}) }}">show</a>
<a href="{{ path('app_drink_type_edit', {'id': drink_type.id}) }}">edit</a> <a href="{{ path('app_drink_type_edit', {'id': drink_type.id}) }}">edit</a>

View file

@ -36,8 +36,12 @@
<td>{{ drink_type.description }}</td> <td>{{ drink_type.description }}</td>
</tr> </tr>
<tr> <tr>
<th>DesiredStock</th> <th>Current Stock</th>
<td>{{ drink_type.desiredStock }}</td> <td>{{ drink_type.currentStock }}</td>
</tr>
<tr>
<th>Wanted Stock</th>
<td>{{ drink_type.wantedStock }}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -87,7 +91,7 @@
<h5 class="card-title">Inventory History</h5> <h5 class="card-title">Inventory History</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
{% if inventory_records|length > 0 %} {% if stock_history|length > 0 %}
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
@ -96,10 +100,10 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for record in inventory_records %} {% for record in stock_history %}
<tr> <tr>
<td>{{ record.createdAt|date('Y-m-d H:i:s') }}</td> <td>{{ record.changeDate|date('Y-m-d H:i:s') }}</td>
<td>{{ record.quantity }}</td> <td>{{ record.newValue }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -119,7 +123,7 @@
<h5 class="card-title">Desired Stock History</h5> <h5 class="card-title">Desired Stock History</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
{% if desired_stock_history|length > 0 %} {% if wanted_history|length > 0 %}
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
@ -128,7 +132,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for log in desired_stock_history %} {% for log in wanted_history %}
<tr> <tr>
<td>{{ log.changeDate|date('Y-m-d H:i:s') }}</td> <td>{{ log.changeDate|date('Y-m-d H:i:s') }}</td>
<td>{{ log.newValue }}</td> <td>{{ log.newValue }}</td>

View file

@ -5,35 +5,6 @@
{% block body %} {% block body %}
<div class="container"> <div class="container">
<h1>Drink Inventory</h1> <h1>Drink Inventory</h1>
{% if low is not same as([]) %}
<div class="card">
<div class="card-header">
<h5 class="card-title">Low Stock Alert</h5>
</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<tr>
<th>Drink Name</th>
<th>Current Stock</th>
<th>Desired Stock</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for lowStock in low %}
<tr>
<td><a href="{{ path('app_drink_type_show', {'id': lowStock.record.drinkType.id}) }}">{{ lowStock.record.drinkType.name }}</a></td>
<td>{{ lowStock.record.quantity }}</td>
<td>{{ lowStock.record.drinkType.desiredStock }}</td>
<td>{{ lowStock.stock.value|capitalize }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h5 class="card-title">Drink Inventory Overview</h5> <h5 class="card-title">Drink Inventory Overview</h5>
@ -43,36 +14,22 @@
<thead> <thead>
<tr> <tr>
<th>Drink Name</th> <th>Drink Name</th>
<th>Description</th>
<th>Current Stock</th> <th>Current Stock</th>
<th>Desired Stock</th> <th>Wanted Stock</th>
<th>Status</th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for drinkStock in drinkStocks %} {% for drinkType in drinkTypes %}
{% set rowClass = '' %} <tr>
{% if drinkStock.stock.value == 'critical' %} <td>
{% set rowClass = 'table-danger' %} <a href="{{ path('app_drink_type_show', {'id': drinkType.id}) }}">{{ drinkType.name }}</a>
{% elseif drinkStock.stock.value == 'low' %} </td>
{% set rowClass = 'table-warning' %} <td>{{ drinkType.description }}</td>
{% elseif drinkStock.stock.value == 'high' %} <td>{{ drinkType.currentStock }}</td>
{% set rowClass = 'table-success' %} <td>{{ drinkType.wantedStock }}</td>
{% endif %}
<tr class="{{ rowClass }}">
<td><a href="{{ path('app_drink_type_show', {'id': drinkStock.record.drinkType.id}) }}">{{ drinkStock.record.drinkType.name }}</a></td>
<td>{{ drinkStock.record.quantity }}</td>
<td>{{ drinkStock.record.drinkType.desiredStock }}</td>
<td>{{ drinkStock.stock.value|capitalize }}</td>
<td> <td>
<a href="{{ path('app_inventory_record_modal', {drinkType: drinkStock.record.drinkType.id}) }}"
class="btn btn-primary"
hx-get="{{ path('app_inventory_record_modal', {drinkType: drinkStock.record.drinkType.id}) }}"
hx-target="#htmxModalBody"
hx-trigger="click"
data-bs-toggle="modal"
data-bs-target="#htmxModal"
data-drink-name="{{ drinkStock.record.drinkType.name }}">Update Stock</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
@ -81,7 +38,6 @@
<div class="mt-3"> <div class="mt-3">
<a href="{{ path('app_drink_type_index') }}" class="btn btn-primary">View All Drinks</a> <a href="{{ path('app_drink_type_index') }}" class="btn btn-primary">View All Drinks</a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -14,5 +14,5 @@ test('Hello World', function (): void {
// Validate a successful response and some content // Validate a successful response and some content
$this->assertResponseIsSuccessful(); $this->assertResponseIsSuccessful();
$this->assertSelectorTextContains('h1', 'Hello World'); $this->assertSelectorTextContains('h1', 'Drink Inventory');
}); });