Compare commits

..
9 Commits
24 changed files with 490 additions and 421 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 KiB

After

Width:  |  Height:  |  Size: 912 KiB

+18 -15
View File
@@ -52,7 +52,7 @@ Clone this repository by running:
git clone --branch v0.1 --single-branch https://github.com/theis-js/stockhome.git git clone --branch v0.1 --single-branch https://github.com/theis-js/stockhome.git
``` ```
You can replace `v0.1` with the latest release tag to get the latest version of the stack. You can also use `dev` to get You can replace `v0.1` with any other release tag to get your desired version of the repo. You can also use `dev` to get
the latest development version, but keep in mind that it may contain bugs and errors. the latest development version, but keep in mind that it may contain bugs and errors.
View the available version tags here: [Releases](https://github.com/theis-js/stockhome/tags) View the available version tags here: [Releases](https://github.com/theis-js/stockhome/tags)
@@ -69,7 +69,7 @@ AUTH_SIGNATURE=
BACKEND_HOST=stockhome-backend BACKEND_HOST=stockhome-backend
``` ```
Make sure that you have set an secure root password and a secure signature. Make sure that you have set a secure root password and a secure signature.
> **Note** These three values cannot contain special characters. > **Note** These three values cannot contain special characters.
@@ -87,7 +87,7 @@ First, navigate into the root directory of this repository and run:
docker compose up -d --build docker compose up -d --build
``` ```
The database and all necessary services are started and initialised automatically. The database and all necessary services are started and initialized automatically.
### 5. First login ### 5. First login
@@ -115,22 +115,25 @@ repository! [Report a bug](https://github.com/theis-js/stockhome/issues/new/choo
## Update ## Update
To update stockhome to the latest version, navigate into the root directory of this repository and run: To update Stockhome to the latest version, navigate into the root directory of this repository and run:
```shell
git fetch --all --tags && git checkout "$(git describe --tags "$(git rev-list --tags --max-count=1)")"
```
To rebuild the containers run:
```shell ```shell
git pull
latesttag=$(git describe --tags)
git checkout ${latesttag}
docker compose up -d --build docker compose up -d --build
``` ```
To update to a specific version, replace `latesttag` with the version tag you want to update to. You can view the To update/downgrade to a specific version, run the command below. You can replace `v0.1` with the tag/version you want.
available version tags here: [Releases](https://github.com/theis-js/stockhome/tags) You can find all Releases her: [Releases](https://github.com/theis-js/stockhome/tags).
**Example to downgrade/update to version `v0.1`:** **Example to downgrade/update to version `v0.1`:**
```shell ```shell
git pull git fetch --all
git checkout v0.1 git checkout v0.1
docker compose up -d --build docker compose up -d --build
``` ```
@@ -143,20 +146,20 @@ docker compose up -d --build
- Visual Studio Code (or any other IDE) - Visual Studio Code (or any other IDE)
- Cloned the repository - Cloned the repository
### Start backend and database ### Initialize repository dependencies
First, navigate into the root directory of this repository and run: First, navigate into the root directory of this repository and run:
```shell ```shell
docker compose -f docker-compose.dev.yml up -d --build npm install
``` ```
### Start frontend ### Start development environment
Navigate into the `frontend` directory and run: Stay in the root directory and run:
```shell ```shell
npm install npm run build:shared
npm run dev npm run dev
``` ```
+140 -104
View File
@@ -1,133 +1,169 @@
-- ============================================================= -- =============================================================
-- STOCKHOME MOCK DATA -- STOCKHOME MOCK DATA (EN)
-- Generates: 5 Storage Locations, ~100 Products -- Generates: 5 Storage Locations, 94 Products
--
-- Safe to re-run: storage locations are upserted by name, and
-- products reference the locations by looked-up UUID rather
-- than a hardcoded literal. This avoids the FK error 1452 that
-- occurs when a location with the same name already exists
-- (storage_locations.name is UNIQUE) with a different UUID.
--
-- Uncomment the DELETE below if you want a clean product table.
-- ============================================================= -- =============================================================
USE stockhome; USE stockhome;
-- Optional clean slate for products only (keeps user/app settings):
-- DELETE FROM products;
-- ============================================= -- =============================================
-- Storage Locations (5) -- Storage Locations (5)
-- ============================================= -- =============================================
INSERT INTO storage_locations (uuid, name, description) VALUES INSERT INTO storage_locations (uuid, name, description)
(UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), 'Main Freezer', 'Large chest freezer in the basement'), VALUES (UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), 'Main Freezer', 'Large chest freezer in the basement'),
(UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), 'Kitchen Freezer', 'Freezer compartment of the kitchen fridge'), (UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), 'Kitchen Freezer',
(UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), 'Pantry', 'Dry goods storage in the hallway'), 'Freezer compartment of the kitchen fridge'),
(UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), 'Kitchen Fridge', 'Main refrigerator in the kitchen'), (UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), 'Pantry', 'Dry goods storage in the hallway'),
(UUID_TO_BIN('a1000000-0000-0000-0000-000000000005'), 'Cellar Shelf', 'Cool storage shelves in the cellar'); (UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), 'Kitchen Fridge', 'Main refrigerator in the kitchen'),
(UUID_TO_BIN('a1000000-0000-0000-0000-000000000005'), 'Cellar Shelf', 'Cool storage shelves in the cellar')
ON DUPLICATE KEY UPDATE description = VALUES(description);
-- ============================================= -- =============================================
-- Products (~100) -- Resolve the actual UUIDs (works whether the rows were just
-- inserted or already existed with different UUIDs)
-- =============================================
SET @loc_main_freezer = (SELECT uuid
FROM storage_locations
WHERE name = 'Main Freezer');
SET @loc_kitchen_freezer = (SELECT uuid
FROM storage_locations
WHERE name = 'Kitchen Freezer');
SET @loc_pantry = (SELECT uuid
FROM storage_locations
WHERE name = 'Pantry');
SET @loc_kitchen_fridge = (SELECT uuid
FROM storage_locations
WHERE name = 'Kitchen Fridge');
SET @loc_cellar_shelf = (SELECT uuid
FROM storage_locations
WHERE name = 'Cellar Shelf');
-- =============================================
-- Products (94)
-- uuid, picture, created_at, updated_at and deleted rely on
-- their column defaults.
-- Self-frozen items have a bottling_date. -- Self-frozen items have a bottling_date.
-- Store-bought items have bottling_date = NULL. -- Store-bought items have bottling_date = NULL.
-- ============================================= -- =============================================
INSERT INTO products (uuid, name, description, price, amount, storage_location, expiry_date, bottling_date, picture, deleted) VALUES INSERT INTO products (name, description, price, amount, storage_location, expiry_date, bottling_date)
VALUES
-- ── Self-frozen items (Main Freezer) ── -- ── Self-frozen items (Main Freezer) ──
(UUID_TO_BIN(UUID()), 'Strawberry Puree', 'Blended fresh strawberries', NULL, 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-12-15', '2026-06-01', NULL, FALSE), ('Strawberry Puree', 'Blended fresh strawberries', NULL, 4, @loc_main_freezer, '2026-12-15', '2026-06-01'),
(UUID_TO_BIN(UUID()), 'Tomato Sauce', 'Homemade marinara sauce', NULL, 6, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2027-01-10', '2026-05-20', NULL, FALSE), ('Tomato Sauce', 'Homemade marinara sauce', NULL, 6, @loc_main_freezer, '2027-01-10', '2026-05-20'),
(UUID_TO_BIN(UUID()), 'Chicken Broth', 'Slow-cooked bone broth', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-11-30', '2026-04-15', NULL, FALSE), ('Chicken Broth', 'Slow-cooked bone broth', NULL, 3, @loc_main_freezer, '2026-11-30', '2026-04-15'),
(UUID_TO_BIN(UUID()), 'Blanched Green Beans', 'Garden green beans, blanched', NULL, 5, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2027-02-01', '2026-05-28', NULL, FALSE), ('Blanched Green Beans', 'Garden green beans, blanched', NULL, 5, @loc_main_freezer, '2027-02-01', '2026-05-28'),
(UUID_TO_BIN(UUID()), 'Pesto Cubes', 'Basil pesto in ice cube trays', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-12-01', '2026-05-10', NULL, FALSE), ('Pesto Cubes', 'Basil pesto in ice cube trays', NULL, 2, @loc_main_freezer, '2026-12-01', '2026-05-10'),
(UUID_TO_BIN(UUID()), 'Raspberry Jam', 'Homemade seedless raspberry jam', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2027-03-01', '2026-06-02', NULL, FALSE), ('Raspberry Jam', 'Homemade seedless raspberry jam', NULL, 3, @loc_main_freezer, '2027-03-01', '2026-06-02'),
(UUID_TO_BIN(UUID()), 'Beef Stew', 'Leftover beef stew, portioned', NULL, 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-10-15', '2026-04-20', NULL, FALSE), ('Beef Stew', 'Leftover beef stew, portioned', NULL, 4, @loc_main_freezer, '2026-10-15', '2026-04-20'),
(UUID_TO_BIN(UUID()), 'Blanched Spinach', 'Fresh spinach, blanched and pressed', NULL, 6, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2027-01-20', '2026-05-15', NULL, FALSE), ('Blanched Spinach', 'Fresh spinach, blanched and pressed', NULL, 6, @loc_main_freezer, '2027-01-20', '2026-05-15'),
(UUID_TO_BIN(UUID()), 'Mango Chunks', 'Diced ripe mangoes', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-12-20', '2026-05-25', NULL, FALSE), ('Mango Chunks', 'Diced ripe mangoes', NULL, 3, @loc_main_freezer, '2026-12-20', '2026-05-25'),
(UUID_TO_BIN(UUID()), 'Carrot Soup', 'Pureed carrot ginger soup', NULL, 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-11-01', '2026-04-10', NULL, FALSE), ('Carrot Soup', 'Pureed carrot ginger soup', NULL, 4, @loc_main_freezer, '2026-11-01', '2026-04-10'),
-- ── Self-frozen items (Kitchen Freezer) ── -- ── Self-frozen items (Kitchen Freezer) ──
(UUID_TO_BIN(UUID()), 'Blueberry Mix', 'Mixed blueberries from the garden', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2026-12-10', '2026-06-03', NULL, FALSE), ('Blueberry Mix', 'Mixed blueberries from the garden', NULL, 2, @loc_kitchen_freezer, '2026-12-10', '2026-06-03'),
(UUID_TO_BIN(UUID()), 'Zucchini Slices', 'Sliced and blanched zucchini', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-01-15', '2026-05-18', NULL, FALSE), ('Zucchini Slices', 'Sliced and blanched zucchini', NULL, 3, @loc_kitchen_freezer, '2027-01-15', '2026-05-18'),
(UUID_TO_BIN(UUID()), 'Apple Sauce', 'Homemade cinnamon apple sauce', NULL, 5, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-02-10', '2026-05-22', NULL, FALSE), ('Apple Sauce', 'Homemade cinnamon apple sauce', NULL, 5, @loc_kitchen_freezer, '2027-02-10', '2026-05-22'),
(UUID_TO_BIN(UUID()), 'Bolognese Sauce', 'Classic meat sauce, portioned', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2026-11-20', '2026-04-25', NULL, FALSE), ('Bolognese Sauce', 'Classic meat sauce, portioned', NULL, 3, @loc_kitchen_freezer, '2026-11-20', '2026-04-25'),
(UUID_TO_BIN(UUID()), 'Herb Butter', 'Parsley and garlic butter logs', NULL, 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2026-12-30', '2026-05-30', NULL, FALSE), ('Herb Butter', 'Parsley and garlic butter logs', NULL, 4, @loc_kitchen_freezer, '2026-12-30', '2026-05-30'),
(UUID_TO_BIN(UUID()), 'Peach Slices', 'Frozen ripe peach slices', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-01-05', '2026-06-01', NULL, FALSE), ('Peach Slices', 'Frozen ripe peach slices', NULL, 2, @loc_kitchen_freezer, '2027-01-05', '2026-06-01'),
(UUID_TO_BIN(UUID()), 'Corn Kernels', 'Fresh sweet corn, cut off the cob', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-02-20', '2026-05-12', NULL, FALSE), ('Corn Kernels', 'Fresh sweet corn, cut off the cob', NULL, 3, @loc_kitchen_freezer, '2027-02-20', '2026-05-12'),
(UUID_TO_BIN(UUID()), 'Pumpkin Puree', 'Roasted and pureed butternut squash', NULL, 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-03-10', '2026-05-08', NULL, FALSE), ('Pumpkin Puree', 'Roasted and pureed butternut squash', NULL, 4, @loc_kitchen_freezer, '2027-03-10', '2026-05-08'),
(UUID_TO_BIN(UUID()), 'Lemon Juice Cubes', 'Fresh lemon juice frozen in cubes', NULL, 6, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-04-01', '2026-06-02', NULL, FALSE), ('Lemon Juice Cubes', 'Fresh lemon juice frozen in cubes', NULL, 6, @loc_kitchen_freezer, '2027-04-01', '2026-06-02'),
(UUID_TO_BIN(UUID()), 'Minced Garlic', 'Peeled and minced garlic cloves', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-01-25', '2026-05-14', NULL, FALSE), ('Minced Garlic', 'Peeled and minced garlic cloves', NULL, 2, @loc_kitchen_freezer, '2027-01-25', '2026-05-14'),
-- ── Self-frozen items (split across storages) ── -- ── Self-frozen items (split across storages) ──
(UUID_TO_BIN(UUID()), 'Vegetable Stock', 'Homemade veggie stock', NULL, 5, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-12-05', '2026-04-30', NULL, FALSE), ('Vegetable Stock', 'Homemade veggie stock', NULL, 5, @loc_main_freezer, '2026-12-05', '2026-04-30'),
(UUID_TO_BIN(UUID()), 'Rhubarb Compote', 'Stewed rhubarb with sugar', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2027-01-30', '2026-05-05', NULL, FALSE), ('Rhubarb Compote', 'Stewed rhubarb with sugar', NULL, 3, @loc_main_freezer, '2027-01-30', '2026-05-05'),
(UUID_TO_BIN(UUID()), 'Cherry Halves', 'Pitted sour cherries', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-12-25', '2026-06-01', NULL, FALSE), ('Cherry Halves', 'Pitted sour cherries', NULL, 2, @loc_main_freezer, '2026-12-25', '2026-06-01'),
(UUID_TO_BIN(UUID()), 'Cauliflower Florets', 'Blanched cauliflower pieces', NULL, 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-02-15', '2026-05-19', NULL, FALSE), ('Cauliflower Florets', 'Blanched cauliflower pieces', NULL, 4, @loc_kitchen_freezer, '2027-02-15', '2026-05-19'),
(UUID_TO_BIN(UUID()), 'Plum Jam', 'Homemade plum jam', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2027-03-20', '2026-05-27', NULL, FALSE), ('Plum Jam', 'Homemade plum jam', NULL, 3, @loc_main_freezer, '2027-03-20', '2026-05-27'),
(UUID_TO_BIN(UUID()), 'Mushroom Duxelles', 'Finely chopped sauteed mushrooms', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2026-11-10', '2026-04-18', NULL, FALSE), ('Mushroom Duxelles', 'Finely chopped sauteed mushrooms', NULL, 2, @loc_kitchen_freezer, '2026-11-10', '2026-04-18'),
(UUID_TO_BIN(UUID()), 'Chili Con Carne', 'Portioned homemade chili', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-10-30', '2026-04-12', NULL, FALSE), ('Chili Con Carne', 'Portioned homemade chili', NULL, 3, @loc_main_freezer, '2026-10-30', '2026-04-12'),
(UUID_TO_BIN(UUID()), 'Banana Slices', 'Ripe banana slices for smoothies', NULL, 5, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2026-12-08', '2026-06-03', NULL, FALSE), ('Banana Slices', 'Ripe banana slices for smoothies', NULL, 5, @loc_kitchen_freezer, '2026-12-08', '2026-06-03'),
(UUID_TO_BIN(UUID()), 'Parsley Cubes', 'Chopped parsley in olive oil cubes', NULL, 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-04-15', '2026-05-31', NULL, FALSE), ('Parsley Cubes', 'Chopped parsley in olive oil cubes', NULL, 4, @loc_kitchen_freezer, '2027-04-15', '2026-05-31'),
(UUID_TO_BIN(UUID()), 'Lentil Soup', 'Thick homemade lentil soup', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-11-25', '2026-04-22', NULL, FALSE), ('Lentil Soup', 'Thick homemade lentil soup', NULL, 3, @loc_main_freezer, '2026-11-25', '2026-04-22'),
(UUID_TO_BIN(UUID()), 'Blackberry Puree', 'Strained wild blackberries', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2027-01-12', '2026-06-02', NULL, FALSE), ('Blackberry Puree', 'Strained wild blackberries', NULL, 2, @loc_main_freezer, '2027-01-12', '2026-06-02'),
(UUID_TO_BIN(UUID()), 'Roasted Bell Peppers', 'Peeled roasted red peppers', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-02-28', '2026-05-16', NULL, FALSE), ('Roasted Bell Peppers', 'Peeled roasted red peppers', NULL, 3, @loc_kitchen_freezer, '2027-02-28', '2026-05-16'),
(UUID_TO_BIN(UUID()), 'Goulash', 'Hungarian-style beef goulash', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-10-20', '2026-04-08', NULL, FALSE), ('Goulash', 'Hungarian-style beef goulash', NULL, 2, @loc_main_freezer, '2026-10-20', '2026-04-08'),
(UUID_TO_BIN(UUID()), 'Mixed Berry Smoothie Pack', 'Pre-portioned smoothie mix', NULL, 6, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2026-12-18', '2026-06-04', NULL, FALSE), ('Mixed Berry Smoothie Pack', 'Pre-portioned smoothie mix', NULL, 6, @loc_kitchen_freezer, '2026-12-18', '2026-06-04'),
(UUID_TO_BIN(UUID()), 'Leek Cream Soup', 'Pureed leek and potato soup', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-11-15', '2026-04-28', NULL, FALSE), ('Leek Cream Soup', 'Pureed leek and potato soup', NULL, 3, @loc_main_freezer, '2026-11-15', '2026-04-28'),
(UUID_TO_BIN(UUID()), 'Diced Onions', 'Pre-diced yellow onions', NULL, 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-03-05', '2026-05-24', NULL, FALSE), ('Diced Onions', 'Pre-diced yellow onions', NULL, 4, @loc_kitchen_freezer, '2027-03-05', '2026-05-24'),
(UUID_TO_BIN(UUID()), 'Grape Juice Concentrate', 'Reduced grape juice for desserts', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2027-02-05', '2026-05-11', NULL, FALSE), ('Grape Juice Concentrate', 'Reduced grape juice for desserts', NULL, 2, @loc_main_freezer, '2027-02-05', '2026-05-11'),
(UUID_TO_BIN(UUID()), 'Currant Jelly', 'Red currant jelly', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2027-04-10', '2026-06-01', NULL, FALSE), ('Currant Jelly', 'Red currant jelly', NULL, 3, @loc_main_freezer, '2027-04-10', '2026-06-01'),
(UUID_TO_BIN(UUID()), 'Broccoli Florets', 'Blanched broccoli pieces', NULL, 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-01-08', '2026-05-20', NULL, FALSE), ('Broccoli Florets', 'Blanched broccoli pieces', NULL, 4, @loc_kitchen_freezer, '2027-01-08', '2026-05-20'),
(UUID_TO_BIN(UUID()), 'Sweet Potato Mash', 'Roasted and mashed sweet potatoes', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-12-28', '2026-05-17', NULL, FALSE), ('Sweet Potato Mash', 'Roasted and mashed sweet potatoes', NULL, 3, @loc_main_freezer, '2026-12-28', '2026-05-17'),
(UUID_TO_BIN(UUID()), 'Apricot Halves', 'Frozen ripe apricot halves', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-02-12', '2026-06-03', NULL, FALSE), ('Apricot Halves', 'Frozen ripe apricot halves', NULL, 2, @loc_kitchen_freezer, '2027-02-12', '2026-06-03'),
(UUID_TO_BIN(UUID()), 'Minestrone', 'Chunky Italian vegetable soup', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-11-08', '2026-04-14', NULL, FALSE), ('Minestrone', 'Chunky Italian vegetable soup', NULL, 3, @loc_main_freezer, '2026-11-08', '2026-04-14'),
(UUID_TO_BIN(UUID()), 'Pea Puree', 'Fresh garden peas, pureed', NULL, 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-03-15', '2026-05-26', NULL, FALSE), ('Pea Puree', 'Fresh garden peas, pureed', NULL, 4, @loc_kitchen_freezer, '2027-03-15', '2026-05-26'),
(UUID_TO_BIN(UUID()), 'Cranberry Sauce', 'Homemade whole berry cranberry sauce', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2027-01-18', '2026-05-09', NULL, FALSE), ('Cranberry Sauce', 'Homemade whole berry cranberry sauce', NULL, 2, @loc_main_freezer, '2027-01-18', '2026-05-09'),
(UUID_TO_BIN(UUID()), 'Egg Noodles', 'Homemade egg noodles, pre-cooked', NULL, 5, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2026-12-12', '2026-05-29', NULL, FALSE), ('Egg Noodles', 'Homemade egg noodles, pre-cooked', NULL, 5, @loc_kitchen_freezer, '2026-12-12', '2026-05-29'),
(UUID_TO_BIN(UUID()), 'Gooseberry Compote', 'Stewed gooseberries', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2027-02-22', '2026-06-02', NULL, FALSE), ('Gooseberry Compote', 'Stewed gooseberries', NULL, 2, @loc_main_freezer, '2027-02-22', '2026-06-02'),
(UUID_TO_BIN(UUID()), 'Creamed Corn', 'Homemade creamed corn', NULL, 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-01-28', '2026-05-21', NULL, FALSE), ('Creamed Corn', 'Homemade creamed corn', NULL, 3, @loc_kitchen_freezer, '2027-01-28', '2026-05-21'),
(UUID_TO_BIN(UUID()), 'Chicken Curry', 'Portioned Thai green curry', NULL, 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000001'), '2026-10-25', '2026-04-16', NULL, FALSE), ('Chicken Curry', 'Portioned Thai green curry', NULL, 2, @loc_main_freezer, '2026-10-25', '2026-04-16'),
(UUID_TO_BIN(UUID()), 'Dill Cubes', 'Chopped dill frozen in water cubes', NULL, 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000002'), '2027-04-20', '2026-06-01', NULL, FALSE), ('Dill Cubes', 'Chopped dill frozen in water cubes', NULL, 4, @loc_kitchen_freezer, '2027-04-20', '2026-06-01'),
-- ── Store-bought items (no bottling_date) ── -- ── Store-bought items (no bottling_date) ──
-- Kitchen Fridge -- Kitchen Fridge
(UUID_TO_BIN(UUID()), 'Whole Milk', 'Full-fat milk, 1 liter', '1.19', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-06-14', NULL, NULL, FALSE), ('Whole Milk', 'Full-fat milk, 1 liter', '1.19', 2, @loc_kitchen_fridge, '2026-06-14', NULL),
(UUID_TO_BIN(UUID()), 'Greek Yogurt', 'Plain Greek yogurt, 500g', '2.49', 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-06-20', NULL, NULL, FALSE), ('Greek Yogurt', 'Plain Greek yogurt, 500g', '2.49', 3, @loc_kitchen_fridge, '2026-06-20', NULL),
(UUID_TO_BIN(UUID()), 'Butter', 'Unsalted butter, 250g', '2.29', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-07-15', NULL, NULL, FALSE), ('Butter', 'Unsalted butter, 250g', '2.29', 2, @loc_kitchen_fridge, '2026-07-15', NULL),
(UUID_TO_BIN(UUID()), 'Cheddar Cheese', 'Mature cheddar block, 400g', '3.49', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-08-10', NULL, NULL, FALSE), ('Cheddar Cheese', 'Mature cheddar block, 400g', '3.49', 1, @loc_kitchen_fridge, '2026-08-10', NULL),
(UUID_TO_BIN(UUID()), 'Cream Cheese', 'Philadelphia original, 200g', '1.89', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-06-25', NULL, NULL, FALSE), ('Cream Cheese', 'Philadelphia original, 200g', '1.89', 2, @loc_kitchen_fridge, '2026-06-25', NULL),
(UUID_TO_BIN(UUID()), 'Orange Juice', 'Fresh squeezed, 1 liter', '2.99', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-06-12', NULL, NULL, FALSE), ('Orange Juice', 'Fresh squeezed, 1 liter', '2.99', 1, @loc_kitchen_fridge, '2026-06-12', NULL),
(UUID_TO_BIN(UUID()), 'Eggs', 'Free-range eggs, pack of 10', '3.29', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-06-18', NULL, NULL, FALSE), ('Eggs', 'Free-range eggs, pack of 10', '3.29', 1, @loc_kitchen_fridge, '2026-06-18', NULL),
(UUID_TO_BIN(UUID()), 'Ham Slices', 'Cooked ham, 200g pack', '2.19', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-06-10', NULL, NULL, FALSE), ('Ham Slices', 'Cooked ham, 200g pack', '2.19', 2, @loc_kitchen_fridge, '2026-06-10', NULL),
(UUID_TO_BIN(UUID()), 'Mozzarella', 'Fresh mozzarella ball, 125g', '1.49', 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-06-09', NULL, NULL, FALSE), ('Mozzarella', 'Fresh mozzarella ball, 125g', '1.49', 3, @loc_kitchen_fridge, '2026-06-09', NULL),
(UUID_TO_BIN(UUID()), 'Hummus', 'Classic chickpea hummus, 300g', '2.29', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-06-15', NULL, NULL, FALSE), ('Hummus', 'Classic chickpea hummus, 300g', '2.29', 1, @loc_kitchen_fridge, '2026-06-15', NULL),
-- Pantry -- Pantry
(UUID_TO_BIN(UUID()), 'Pasta Spaghetti', 'Durum wheat spaghetti, 500g', '1.29', 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2028-03-01', NULL, NULL, FALSE), ('Pasta Spaghetti', 'Durum wheat spaghetti, 500g', '1.29', 4, @loc_pantry, '2028-03-01', NULL),
(UUID_TO_BIN(UUID()), 'Basmati Rice', 'Long grain basmati, 1kg', '2.99', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2028-06-01', NULL, NULL, FALSE), ('Basmati Rice', 'Long grain basmati, 1kg', '2.99', 2, @loc_pantry, '2028-06-01', NULL),
(UUID_TO_BIN(UUID()), 'Canned Tomatoes', 'Chopped tomatoes, 400g tin', '0.89', 6, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2028-01-15', NULL, NULL, FALSE), ('Canned Tomatoes', 'Chopped tomatoes, 400g tin', '0.89', 6, @loc_pantry, '2028-01-15', NULL),
(UUID_TO_BIN(UUID()), 'Canned Chickpeas', 'Chickpeas in water, 400g', '0.99', 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2028-04-10', NULL, NULL, FALSE), ('Canned Chickpeas', 'Chickpeas in water, 400g', '0.99', 4, @loc_pantry, '2028-04-10', NULL),
(UUID_TO_BIN(UUID()), 'Olive Oil', 'Extra virgin olive oil, 500ml', '5.99', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2027-09-01', NULL, NULL, FALSE), ('Olive Oil', 'Extra virgin olive oil, 500ml', '5.99', 1, @loc_pantry, '2027-09-01', NULL),
(UUID_TO_BIN(UUID()), 'Peanut Butter', 'Crunchy peanut butter, 350g', '3.49', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2027-02-01', NULL, NULL, FALSE), ('Peanut Butter', 'Crunchy peanut butter, 350g', '3.49', 2, @loc_pantry, '2027-02-01', NULL),
(UUID_TO_BIN(UUID()), 'Honey', 'Raw wildflower honey, 500g', '6.99', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2028-12-01', NULL, NULL, FALSE), ('Honey', 'Raw wildflower honey, 500g', '6.99', 1, @loc_pantry, '2028-12-01', NULL),
(UUID_TO_BIN(UUID()), 'Oats', 'Rolled oats, 1kg', '1.99', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2027-08-01', NULL, NULL, FALSE), ('Oats', 'Rolled oats, 1kg', '1.99', 2, @loc_pantry, '2027-08-01', NULL),
(UUID_TO_BIN(UUID()), 'Flour', 'All-purpose wheat flour, 1kg', '0.99', 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2027-06-01', NULL, NULL, FALSE), ('Flour', 'All-purpose wheat flour, 1kg', '0.99', 3, @loc_pantry, '2027-06-01', NULL),
(UUID_TO_BIN(UUID()), 'Sugar', 'White granulated sugar, 1kg', '1.49', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2029-01-01', NULL, NULL, FALSE), ('Sugar', 'White granulated sugar, 1kg', '1.49', 2, @loc_pantry, '2029-01-01', NULL),
(UUID_TO_BIN(UUID()), 'Canned Tuna', 'Tuna chunks in sunflower oil, 185g', '1.79', 5, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2028-07-01', NULL, NULL, FALSE), ('Canned Tuna', 'Tuna chunks in sunflower oil, 185g', '1.79', 5, @loc_pantry, '2028-07-01', NULL),
(UUID_TO_BIN(UUID()), 'Coconut Milk', 'Full-fat coconut milk, 400ml', '1.59', 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2028-02-01', NULL, NULL, FALSE), ('Coconut Milk', 'Full-fat coconut milk, 400ml', '1.59', 3, @loc_pantry, '2028-02-01', NULL),
(UUID_TO_BIN(UUID()), 'Soy Sauce', 'Naturally brewed soy sauce, 250ml', '2.49', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2028-05-01', NULL, NULL, FALSE), ('Soy Sauce', 'Naturally brewed soy sauce, 250ml', '2.49', 1, @loc_pantry, '2028-05-01', NULL),
(UUID_TO_BIN(UUID()), 'Balsamic Vinegar', 'Aged balsamic vinegar, 250ml', '3.99', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2029-06-01', NULL, NULL, FALSE), ('Balsamic Vinegar', 'Aged balsamic vinegar, 250ml', '3.99', 1, @loc_pantry, '2029-06-01', NULL),
(UUID_TO_BIN(UUID()), 'Dried Lentils', 'Green lentils, 500g', '1.69', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2028-09-01', NULL, NULL, FALSE), ('Dried Lentils', 'Green lentils, 500g', '1.69', 2, @loc_pantry, '2028-09-01', NULL),
(UUID_TO_BIN(UUID()), 'Cornflakes', 'Classic cornflakes, 500g', '2.19', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2027-04-01', NULL, NULL, FALSE), ('Cornflakes', 'Classic cornflakes, 500g', '2.19', 1, @loc_pantry, '2027-04-01', NULL),
(UUID_TO_BIN(UUID()), 'Black Beans', 'Canned black beans, 400g', '1.09', 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2028-08-01', NULL, NULL, FALSE), ('Black Beans', 'Canned black beans, 400g', '1.09', 3, @loc_pantry, '2028-08-01', NULL),
(UUID_TO_BIN(UUID()), 'Mustard', 'Dijon mustard, 200g jar', '1.89', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2027-11-01', NULL, NULL, FALSE), ('Mustard', 'Dijon mustard, 200g jar', '1.89', 1, @loc_pantry, '2027-11-01', NULL),
(UUID_TO_BIN(UUID()), 'Dried Pasta Penne', 'Penne rigate, 500g', '1.19', 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2028-05-15', NULL, NULL, FALSE), ('Dried Pasta Penne', 'Penne rigate, 500g', '1.19', 3, @loc_pantry, '2028-05-15', NULL),
(UUID_TO_BIN(UUID()), 'Maple Syrup', 'Pure Canadian maple syrup, 250ml', '7.49', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000003'), '2028-10-01', NULL, NULL, FALSE), ('Maple Syrup', 'Pure Canadian maple syrup, 250ml', '7.49', 1, @loc_pantry, '2028-10-01', NULL),
-- Cellar Shelf -- Cellar Shelf
(UUID_TO_BIN(UUID()), 'Canned Corn', 'Sweet corn kernels, 340g', '1.09', 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000005'), '2028-03-15', NULL, NULL, FALSE), ('Canned Corn', 'Sweet corn kernels, 340g', '1.09', 4, @loc_cellar_shelf, '2028-03-15', NULL),
(UUID_TO_BIN(UUID()), 'Canned Peas', 'Garden peas, 400g tin', '0.89', 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000005'), '2028-06-10', NULL, NULL, FALSE), ('Canned Peas', 'Garden peas, 400g tin', '0.89', 3, @loc_cellar_shelf, '2028-06-10', NULL),
(UUID_TO_BIN(UUID()), 'Apple Cider Vinegar', 'Organic apple cider vinegar, 500ml', '3.29', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000005'), '2028-11-01', NULL, NULL, FALSE), ('Apple Cider Vinegar', 'Organic apple cider vinegar, 500ml', '3.29', 2, @loc_cellar_shelf, '2028-11-01', NULL),
(UUID_TO_BIN(UUID()), 'Sunflower Oil', 'Refined sunflower oil, 1 liter', '2.49', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000005'), '2027-10-01', NULL, NULL, FALSE), ('Sunflower Oil', 'Refined sunflower oil, 1 liter', '2.49', 1, @loc_cellar_shelf, '2027-10-01', NULL),
(UUID_TO_BIN(UUID()), 'Tomato Paste', 'Double concentrated, 200g tube', '1.29', 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000005'), '2028-01-01', NULL, NULL, FALSE), ('Tomato Paste', 'Double concentrated, 200g tube', '1.29', 3, @loc_cellar_shelf, '2028-01-01', NULL),
(UUID_TO_BIN(UUID()), 'Canned Sardines', 'Sardines in olive oil, 120g', '2.19', 4, UUID_TO_BIN('a1000000-0000-0000-0000-000000000005'), '2028-09-15', NULL, NULL, FALSE), ('Canned Sardines', 'Sardines in olive oil, 120g', '2.19', 4, @loc_cellar_shelf, '2028-09-15', NULL),
(UUID_TO_BIN(UUID()), 'Pickled Cucumbers', 'Whole pickled gherkins, 670g jar', '1.99', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000005'), '2027-12-01', NULL, NULL, FALSE), ('Pickled Cucumbers', 'Whole pickled gherkins, 670g jar', '1.99', 2, @loc_cellar_shelf, '2027-12-01', NULL),
(UUID_TO_BIN(UUID()), 'Jam Strawberry', 'Store-bought strawberry jam, 450g', '2.79', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000005'), '2027-07-01', NULL, NULL, FALSE), ('Jam Strawberry', 'Store-bought strawberry jam, 450g', '2.79', 1, @loc_cellar_shelf, '2027-07-01', NULL),
(UUID_TO_BIN(UUID()), 'Canned Peaches', 'Peach halves in syrup, 420g', '1.69', 3, UUID_TO_BIN('a1000000-0000-0000-0000-000000000005'), '2028-04-01', NULL, NULL, FALSE), ('Canned Peaches', 'Peach halves in syrup, 420g', '1.69', 3, @loc_cellar_shelf, '2028-04-01', NULL),
(UUID_TO_BIN(UUID()), 'Crackers', 'Whole wheat crackers, 200g', '1.89', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000005'), '2027-05-01', NULL, NULL, FALSE), ('Crackers', 'Whole wheat crackers, 200g', '1.89', 2, @loc_cellar_shelf, '2027-05-01', NULL),
-- Additional Kitchen Fridge items -- Additional Kitchen Fridge items
(UUID_TO_BIN(UUID()), 'Salami', 'Italian salami slices, 100g', '2.99', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-06-20', NULL, NULL, FALSE), ('Salami', 'Italian salami slices, 100g', '2.99', 1, @loc_kitchen_fridge, '2026-06-20', NULL),
(UUID_TO_BIN(UUID()), 'Parmesan', 'Parmigiano Reggiano wedge, 200g', '4.99', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-09-01', NULL, NULL, FALSE), ('Parmesan', 'Parmigiano Reggiano wedge, 200g', '4.99', 1, @loc_kitchen_fridge, '2026-09-01', NULL),
(UUID_TO_BIN(UUID()), 'Smoked Salmon', 'Sliced smoked salmon, 100g', '3.99', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-06-08', NULL, NULL, FALSE), ('Smoked Salmon', 'Sliced smoked salmon, 100g', '3.99', 1, @loc_kitchen_fridge, '2026-06-08', NULL),
(UUID_TO_BIN(UUID()), 'Heavy Cream', 'Whipping cream 35%, 200ml', '1.29', 2, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-06-16', NULL, NULL, FALSE), ('Heavy Cream', 'Whipping cream 35%, 200ml', '1.29', 2, @loc_kitchen_fridge, '2026-06-16', NULL),
(UUID_TO_BIN(UUID()), 'Tofu', 'Firm organic tofu, 400g', '2.49', 1, UUID_TO_BIN('a1000000-0000-0000-0000-000000000004'), '2026-06-22', NULL, NULL, FALSE); ('Tofu', 'Firm organic tofu, 400g', '2.49', 1, @loc_kitchen_fridge, '2026-06-22', NULL);
+6 -2
View File
@@ -3,7 +3,7 @@ import { Button, Input } from "@mui/joy";
import { useMutation } from "@tanstack/react-query"; import { useMutation } from "@tanstack/react-query";
import { signInUser } from "../utils/api/auth"; import { signInUser } from "../utils/api/auth";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useNavigate } from "@tanstack/react-router"; import { useNavigate, useSearch } from "@tanstack/react-router";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import type { AlertInterface } from "../misc/interfaces"; import type { AlertInterface } from "../misc/interfaces";
import { MyAlert } from "./MyAlert.tsx"; import { MyAlert } from "./MyAlert.tsx";
@@ -11,6 +11,7 @@ import { MyAlert } from "./MyAlert.tsx";
export const LoginCard = () => { export const LoginCard = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
const search: { loggedOut?: boolean } = useSearch({ from: "/login" });
const [alert, setAlert] = useState<AlertInterface>({ const [alert, setAlert] = useState<AlertInterface>({
isAlert: false, isAlert: false,
type: "neutral", type: "neutral",
@@ -19,12 +20,15 @@ export const LoginCard = () => {
}); });
useEffect(() => { useEffect(() => {
if (search.loggedOut) {
setAlert({ setAlert({
isAlert: true, isAlert: true,
type: "primary", type: "primary",
header: t("success"), header: t("success"),
text: t("logout-success-text"), text: t("logout-success-text"),
}); });
}
void navigate({ to: "/login" });
}, []); }, []);
const form = useForm({ const form = useForm({
@@ -53,7 +57,7 @@ export const LoginCard = () => {
header: "", header: "",
text: "", text: "",
}); });
navigate({ to: "/app/inventory" }); void navigate({ to: "/app/inventory" });
} }
}, },
onError: (error: unknown) => { onError: (error: unknown) => {
+12 -10
View File
@@ -14,10 +14,12 @@ import { useMatchRoute, useNavigate } from "@tanstack/react-router";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { changeTranslation } from "../utils/uxFncs"; import { changeTranslation } from "../utils/uxFncs";
import { useColorScheme } from "@mui/joy/styles"; import { useColorScheme } from "@mui/joy/styles";
import { useLogout } from "../hooks/useLogout.ts";
export const Sidebar = () => { export const Sidebar = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
const { logout } = useLogout();
const matchRoute = useMatchRoute(); const matchRoute = useMatchRoute();
const { mode, setMode } = useColorScheme(); const { mode, setMode } = useColorScheme();
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
@@ -29,7 +31,7 @@ export const Sidebar = () => {
!!matchRoute({ to, fuzzy: false }) ? "soft" : "plain"; !!matchRoute({ to, fuzzy: false }) ? "soft" : "plain";
const handleNavigate = (to: string) => { const handleNavigate = (to: string) => {
navigate({ to }); void navigate({ to });
setIsOpen(false); setIsOpen(false);
}; };
@@ -65,7 +67,14 @@ export const Sidebar = () => {
<Button <Button
variant="soft" variant="soft"
size="sm" size="sm"
className="transition-transform duration-200 ease-out" sx={{
display: "inline-flex",
"@media (min-width: 1024px)": { display: "none" },
"&:hover": {
backgroundColor: "var(--joy-palette-primary-900)",
color: "var(--joy-palette-primary-50)",
},
}}
onClick={() => setIsOpen((open) => !open)} onClick={() => setIsOpen((open) => !open)}
startDecorator={ startDecorator={
<span <span
@@ -76,10 +85,6 @@ export const Sidebar = () => {
{isOpen ? <CloseIcon /> : <MenuIcon />} {isOpen ? <CloseIcon /> : <MenuIcon />}
</span> </span>
} }
sx={{
display: "inline-flex",
"@media (min-width: 1024px)": { display: "none" },
}}
> >
{isOpen ? t("close") : t("menu")} {isOpen ? t("close") : t("menu")}
</Button> </Button>
@@ -154,10 +159,7 @@ export const Sidebar = () => {
{t("settings")} {t("settings")}
</Button> </Button>
<Button <Button
onClick={() => { onClick={logout}
Cookies.remove("token");
handleNavigate("/login?logout=true");
}}
color="danger" color="danger"
startDecorator={<ExitToAppIcon />} startDecorator={<ExitToAppIcon />}
className={btnClass} className={btnClass}
@@ -1,4 +1,11 @@
import { Button, DialogTitle, Input, Modal, ModalDialog, Stack, } from "@mui/joy"; import {
Button,
DialogTitle,
Input,
Modal,
ModalDialog,
Stack,
} from "@mui/joy";
import { useForm } from "@tanstack/react-form"; import { useForm } from "@tanstack/react-form";
import { useMutation } from "@tanstack/react-query"; import { useMutation } from "@tanstack/react-query";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -30,8 +37,6 @@ export const ChangePasswordModal = (props: ChangePasswordProps) => {
newPasswordRep: "", newPasswordRep: "",
}, },
onSubmit: async ({ value }) => { onSubmit: async ({ value }) => {
console.log(value);
if ( if (
value.newPassword === value.newPasswordRep && value.newPassword === value.newPasswordRep &&
value.newPassword !== "" value.newPassword !== ""
+13
View File
@@ -0,0 +1,13 @@
import Cookies from "js-cookie";
import { useNavigate } from "@tanstack/react-router";
export const useLogout = () => {
const navigate = useNavigate();
const logout = () => {
Cookies.remove("token");
void navigate({ to: "/login", search: { loggedOut: true } });
};
return { logout };
};
+4 -4
View File
@@ -1,4 +1,4 @@
import { useEffect, useState } from "react"; import { ChangeEvent, MouseEvent, useEffect, useState } from "react";
import { Avatar, Button, Checkbox, Chip, CircularProgress, Sheet, Table, Typography, } from "@mui/joy"; import { Avatar, Button, Checkbox, Chip, CircularProgress, Sheet, Table, Typography, } from "@mui/joy";
import { useNavigate } from "@tanstack/react-router"; import { useNavigate } from "@tanstack/react-router";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -73,12 +73,12 @@ export const InventoryPage = () => {
mutationFn: (values: string[]) => deleteSelectedProducts(values), mutationFn: (values: string[]) => deleteSelectedProducts(values),
onSuccess: () => { onSuccess: () => {
setSelected([]); setSelected([]);
queryClient.invalidateQueries({ queryKey: ["products"] }); void queryClient.invalidateQueries({ queryKey: ["products"] });
}, },
onError: showError, onError: showError,
}); });
const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>) => { const handleSelectAllClick = (event: ChangeEvent<HTMLInputElement>) => {
if (event.target.checked) { if (event.target.checked) {
setSelected(rows.map((row) => row.id)); setSelected(rows.map((row) => row.id));
return; return;
@@ -86,7 +86,7 @@ export const InventoryPage = () => {
setSelected([]); setSelected([]);
}; };
const handleClick = (_event: React.MouseEvent<unknown>, id: string) => { const handleClick = (_event: MouseEvent<unknown>, id: string) => {
const selectedIndex = selected.indexOf(id); const selectedIndex = selected.indexOf(id);
let newSelected: readonly string[] = []; let newSelected: readonly string[] = [];
if (selectedIndex === -1) { if (selectedIndex === -1) {
+125 -97
View File
@@ -12,12 +12,13 @@ import { Route as rootRouteImport } from './routes/__root'
import { Route as LoginRouteImport } from './routes/login' import { Route as LoginRouteImport } from './routes/login'
import { Route as IndexRouteImport } from './routes/index' import { Route as IndexRouteImport } from './routes/index'
import { Route as AppHiddenLayoutRouteImport } from './routes/app/_hiddenLayout' import { Route as AppHiddenLayoutRouteImport } from './routes/app/_hiddenLayout'
import { Route as AppHiddenLayoutViewProductRouteImport } from './routes/app/_hiddenLayout/view-product' import { Route as AppHiddenLayoutAuthedRouteImport } from './routes/app/_hiddenLayout/_authed'
import { Route as AppHiddenLayoutStoragesRouteImport } from './routes/app/_hiddenLayout/storages'
import { Route as AppHiddenLayoutInventoryRouteImport } from './routes/app/_hiddenLayout/inventory'
import { Route as AppHiddenLayoutAppSettingsRouteImport } from './routes/app/_hiddenLayout/app-settings'
import { Route as AppHiddenLayoutAddProductRouteImport } from './routes/app/_hiddenLayout/add-product'
import { Route as AppHiddenLayoutQuickViewProductRouteImport } from './routes/app/_hiddenLayout/quick-view/product' import { Route as AppHiddenLayoutQuickViewProductRouteImport } from './routes/app/_hiddenLayout/quick-view/product'
import { Route as AppHiddenLayoutAuthedViewProductRouteImport } from './routes/app/_hiddenLayout/_authed/view-product'
import { Route as AppHiddenLayoutAuthedStoragesRouteImport } from './routes/app/_hiddenLayout/_authed/storages'
import { Route as AppHiddenLayoutAuthedInventoryRouteImport } from './routes/app/_hiddenLayout/_authed/inventory'
import { Route as AppHiddenLayoutAuthedAppSettingsRouteImport } from './routes/app/_hiddenLayout/_authed/app-settings'
import { Route as AppHiddenLayoutAuthedAddProductRouteImport } from './routes/app/_hiddenLayout/_authed/add-product'
const LoginRoute = LoginRouteImport.update({ const LoginRoute = LoginRouteImport.update({
id: '/login', id: '/login',
@@ -34,62 +35,67 @@ const AppHiddenLayoutRoute = AppHiddenLayoutRouteImport.update({
path: '/app', path: '/app',
getParentRoute: () => rootRouteImport, getParentRoute: () => rootRouteImport,
} as any) } as any)
const AppHiddenLayoutViewProductRoute = const AppHiddenLayoutAuthedRoute = AppHiddenLayoutAuthedRouteImport.update({
AppHiddenLayoutViewProductRouteImport.update({ id: '/_authed',
id: '/view-product',
path: '/view-product',
getParentRoute: () => AppHiddenLayoutRoute,
} as any)
const AppHiddenLayoutStoragesRoute = AppHiddenLayoutStoragesRouteImport.update({
id: '/storages',
path: '/storages',
getParentRoute: () => AppHiddenLayoutRoute, getParentRoute: () => AppHiddenLayoutRoute,
} as any) } as any)
const AppHiddenLayoutInventoryRoute =
AppHiddenLayoutInventoryRouteImport.update({
id: '/inventory',
path: '/inventory',
getParentRoute: () => AppHiddenLayoutRoute,
} as any)
const AppHiddenLayoutAppSettingsRoute =
AppHiddenLayoutAppSettingsRouteImport.update({
id: '/app-settings',
path: '/app-settings',
getParentRoute: () => AppHiddenLayoutRoute,
} as any)
const AppHiddenLayoutAddProductRoute =
AppHiddenLayoutAddProductRouteImport.update({
id: '/add-product',
path: '/add-product',
getParentRoute: () => AppHiddenLayoutRoute,
} as any)
const AppHiddenLayoutQuickViewProductRoute = const AppHiddenLayoutQuickViewProductRoute =
AppHiddenLayoutQuickViewProductRouteImport.update({ AppHiddenLayoutQuickViewProductRouteImport.update({
id: '/quick-view/product', id: '/quick-view/product',
path: '/quick-view/product', path: '/quick-view/product',
getParentRoute: () => AppHiddenLayoutRoute, getParentRoute: () => AppHiddenLayoutRoute,
} as any) } as any)
const AppHiddenLayoutAuthedViewProductRoute =
AppHiddenLayoutAuthedViewProductRouteImport.update({
id: '/view-product',
path: '/view-product',
getParentRoute: () => AppHiddenLayoutAuthedRoute,
} as any)
const AppHiddenLayoutAuthedStoragesRoute =
AppHiddenLayoutAuthedStoragesRouteImport.update({
id: '/storages',
path: '/storages',
getParentRoute: () => AppHiddenLayoutAuthedRoute,
} as any)
const AppHiddenLayoutAuthedInventoryRoute =
AppHiddenLayoutAuthedInventoryRouteImport.update({
id: '/inventory',
path: '/inventory',
getParentRoute: () => AppHiddenLayoutAuthedRoute,
} as any)
const AppHiddenLayoutAuthedAppSettingsRoute =
AppHiddenLayoutAuthedAppSettingsRouteImport.update({
id: '/app-settings',
path: '/app-settings',
getParentRoute: () => AppHiddenLayoutAuthedRoute,
} as any)
const AppHiddenLayoutAuthedAddProductRoute =
AppHiddenLayoutAuthedAddProductRouteImport.update({
id: '/add-product',
path: '/add-product',
getParentRoute: () => AppHiddenLayoutAuthedRoute,
} as any)
export interface FileRoutesByFullPath { export interface FileRoutesByFullPath {
'/': typeof IndexRoute '/': typeof IndexRoute
'/login': typeof LoginRoute '/login': typeof LoginRoute
'/app': typeof AppHiddenLayoutRouteWithChildren '/app': typeof AppHiddenLayoutAuthedRouteWithChildren
'/app/add-product': typeof AppHiddenLayoutAddProductRoute '/app/add-product': typeof AppHiddenLayoutAuthedAddProductRoute
'/app/app-settings': typeof AppHiddenLayoutAppSettingsRoute '/app/app-settings': typeof AppHiddenLayoutAuthedAppSettingsRoute
'/app/inventory': typeof AppHiddenLayoutInventoryRoute '/app/inventory': typeof AppHiddenLayoutAuthedInventoryRoute
'/app/storages': typeof AppHiddenLayoutStoragesRoute '/app/storages': typeof AppHiddenLayoutAuthedStoragesRoute
'/app/view-product': typeof AppHiddenLayoutViewProductRoute '/app/view-product': typeof AppHiddenLayoutAuthedViewProductRoute
'/app/quick-view/product': typeof AppHiddenLayoutQuickViewProductRoute '/app/quick-view/product': typeof AppHiddenLayoutQuickViewProductRoute
} }
export interface FileRoutesByTo { export interface FileRoutesByTo {
'/': typeof IndexRoute '/': typeof IndexRoute
'/login': typeof LoginRoute '/login': typeof LoginRoute
'/app': typeof AppHiddenLayoutRouteWithChildren '/app': typeof AppHiddenLayoutAuthedRouteWithChildren
'/app/add-product': typeof AppHiddenLayoutAddProductRoute '/app/add-product': typeof AppHiddenLayoutAuthedAddProductRoute
'/app/app-settings': typeof AppHiddenLayoutAppSettingsRoute '/app/app-settings': typeof AppHiddenLayoutAuthedAppSettingsRoute
'/app/inventory': typeof AppHiddenLayoutInventoryRoute '/app/inventory': typeof AppHiddenLayoutAuthedInventoryRoute
'/app/storages': typeof AppHiddenLayoutStoragesRoute '/app/storages': typeof AppHiddenLayoutAuthedStoragesRoute
'/app/view-product': typeof AppHiddenLayoutViewProductRoute '/app/view-product': typeof AppHiddenLayoutAuthedViewProductRoute
'/app/quick-view/product': typeof AppHiddenLayoutQuickViewProductRoute '/app/quick-view/product': typeof AppHiddenLayoutQuickViewProductRoute
} }
export interface FileRoutesById { export interface FileRoutesById {
@@ -97,11 +103,12 @@ export interface FileRoutesById {
'/': typeof IndexRoute '/': typeof IndexRoute
'/login': typeof LoginRoute '/login': typeof LoginRoute
'/app/_hiddenLayout': typeof AppHiddenLayoutRouteWithChildren '/app/_hiddenLayout': typeof AppHiddenLayoutRouteWithChildren
'/app/_hiddenLayout/add-product': typeof AppHiddenLayoutAddProductRoute '/app/_hiddenLayout/_authed': typeof AppHiddenLayoutAuthedRouteWithChildren
'/app/_hiddenLayout/app-settings': typeof AppHiddenLayoutAppSettingsRoute '/app/_hiddenLayout/_authed/add-product': typeof AppHiddenLayoutAuthedAddProductRoute
'/app/_hiddenLayout/inventory': typeof AppHiddenLayoutInventoryRoute '/app/_hiddenLayout/_authed/app-settings': typeof AppHiddenLayoutAuthedAppSettingsRoute
'/app/_hiddenLayout/storages': typeof AppHiddenLayoutStoragesRoute '/app/_hiddenLayout/_authed/inventory': typeof AppHiddenLayoutAuthedInventoryRoute
'/app/_hiddenLayout/view-product': typeof AppHiddenLayoutViewProductRoute '/app/_hiddenLayout/_authed/storages': typeof AppHiddenLayoutAuthedStoragesRoute
'/app/_hiddenLayout/_authed/view-product': typeof AppHiddenLayoutAuthedViewProductRoute
'/app/_hiddenLayout/quick-view/product': typeof AppHiddenLayoutQuickViewProductRoute '/app/_hiddenLayout/quick-view/product': typeof AppHiddenLayoutQuickViewProductRoute
} }
export interface FileRouteTypes { export interface FileRouteTypes {
@@ -132,11 +139,12 @@ export interface FileRouteTypes {
| '/' | '/'
| '/login' | '/login'
| '/app/_hiddenLayout' | '/app/_hiddenLayout'
| '/app/_hiddenLayout/add-product' | '/app/_hiddenLayout/_authed'
| '/app/_hiddenLayout/app-settings' | '/app/_hiddenLayout/_authed/add-product'
| '/app/_hiddenLayout/inventory' | '/app/_hiddenLayout/_authed/app-settings'
| '/app/_hiddenLayout/storages' | '/app/_hiddenLayout/_authed/inventory'
| '/app/_hiddenLayout/view-product' | '/app/_hiddenLayout/_authed/storages'
| '/app/_hiddenLayout/_authed/view-product'
| '/app/_hiddenLayout/quick-view/product' | '/app/_hiddenLayout/quick-view/product'
fileRoutesById: FileRoutesById fileRoutesById: FileRoutesById
} }
@@ -169,39 +177,11 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AppHiddenLayoutRouteImport preLoaderRoute: typeof AppHiddenLayoutRouteImport
parentRoute: typeof rootRouteImport parentRoute: typeof rootRouteImport
} }
'/app/_hiddenLayout/view-product': { '/app/_hiddenLayout/_authed': {
id: '/app/_hiddenLayout/view-product' id: '/app/_hiddenLayout/_authed'
path: '/view-product' path: ''
fullPath: '/app/view-product' fullPath: '/app'
preLoaderRoute: typeof AppHiddenLayoutViewProductRouteImport preLoaderRoute: typeof AppHiddenLayoutAuthedRouteImport
parentRoute: typeof AppHiddenLayoutRoute
}
'/app/_hiddenLayout/storages': {
id: '/app/_hiddenLayout/storages'
path: '/storages'
fullPath: '/app/storages'
preLoaderRoute: typeof AppHiddenLayoutStoragesRouteImport
parentRoute: typeof AppHiddenLayoutRoute
}
'/app/_hiddenLayout/inventory': {
id: '/app/_hiddenLayout/inventory'
path: '/inventory'
fullPath: '/app/inventory'
preLoaderRoute: typeof AppHiddenLayoutInventoryRouteImport
parentRoute: typeof AppHiddenLayoutRoute
}
'/app/_hiddenLayout/app-settings': {
id: '/app/_hiddenLayout/app-settings'
path: '/app-settings'
fullPath: '/app/app-settings'
preLoaderRoute: typeof AppHiddenLayoutAppSettingsRouteImport
parentRoute: typeof AppHiddenLayoutRoute
}
'/app/_hiddenLayout/add-product': {
id: '/app/_hiddenLayout/add-product'
path: '/add-product'
fullPath: '/app/add-product'
preLoaderRoute: typeof AppHiddenLayoutAddProductRouteImport
parentRoute: typeof AppHiddenLayoutRoute parentRoute: typeof AppHiddenLayoutRoute
} }
'/app/_hiddenLayout/quick-view/product': { '/app/_hiddenLayout/quick-view/product': {
@@ -211,24 +191,72 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AppHiddenLayoutQuickViewProductRouteImport preLoaderRoute: typeof AppHiddenLayoutQuickViewProductRouteImport
parentRoute: typeof AppHiddenLayoutRoute parentRoute: typeof AppHiddenLayoutRoute
} }
'/app/_hiddenLayout/_authed/view-product': {
id: '/app/_hiddenLayout/_authed/view-product'
path: '/view-product'
fullPath: '/app/view-product'
preLoaderRoute: typeof AppHiddenLayoutAuthedViewProductRouteImport
parentRoute: typeof AppHiddenLayoutAuthedRoute
}
'/app/_hiddenLayout/_authed/storages': {
id: '/app/_hiddenLayout/_authed/storages'
path: '/storages'
fullPath: '/app/storages'
preLoaderRoute: typeof AppHiddenLayoutAuthedStoragesRouteImport
parentRoute: typeof AppHiddenLayoutAuthedRoute
}
'/app/_hiddenLayout/_authed/inventory': {
id: '/app/_hiddenLayout/_authed/inventory'
path: '/inventory'
fullPath: '/app/inventory'
preLoaderRoute: typeof AppHiddenLayoutAuthedInventoryRouteImport
parentRoute: typeof AppHiddenLayoutAuthedRoute
}
'/app/_hiddenLayout/_authed/app-settings': {
id: '/app/_hiddenLayout/_authed/app-settings'
path: '/app-settings'
fullPath: '/app/app-settings'
preLoaderRoute: typeof AppHiddenLayoutAuthedAppSettingsRouteImport
parentRoute: typeof AppHiddenLayoutAuthedRoute
}
'/app/_hiddenLayout/_authed/add-product': {
id: '/app/_hiddenLayout/_authed/add-product'
path: '/add-product'
fullPath: '/app/add-product'
preLoaderRoute: typeof AppHiddenLayoutAuthedAddProductRouteImport
parentRoute: typeof AppHiddenLayoutAuthedRoute
}
} }
} }
interface AppHiddenLayoutAuthedRouteChildren {
AppHiddenLayoutAuthedAddProductRoute: typeof AppHiddenLayoutAuthedAddProductRoute
AppHiddenLayoutAuthedAppSettingsRoute: typeof AppHiddenLayoutAuthedAppSettingsRoute
AppHiddenLayoutAuthedInventoryRoute: typeof AppHiddenLayoutAuthedInventoryRoute
AppHiddenLayoutAuthedStoragesRoute: typeof AppHiddenLayoutAuthedStoragesRoute
AppHiddenLayoutAuthedViewProductRoute: typeof AppHiddenLayoutAuthedViewProductRoute
}
const AppHiddenLayoutAuthedRouteChildren: AppHiddenLayoutAuthedRouteChildren = {
AppHiddenLayoutAuthedAddProductRoute: AppHiddenLayoutAuthedAddProductRoute,
AppHiddenLayoutAuthedAppSettingsRoute: AppHiddenLayoutAuthedAppSettingsRoute,
AppHiddenLayoutAuthedInventoryRoute: AppHiddenLayoutAuthedInventoryRoute,
AppHiddenLayoutAuthedStoragesRoute: AppHiddenLayoutAuthedStoragesRoute,
AppHiddenLayoutAuthedViewProductRoute: AppHiddenLayoutAuthedViewProductRoute,
}
const AppHiddenLayoutAuthedRouteWithChildren =
AppHiddenLayoutAuthedRoute._addFileChildren(
AppHiddenLayoutAuthedRouteChildren,
)
interface AppHiddenLayoutRouteChildren { interface AppHiddenLayoutRouteChildren {
AppHiddenLayoutAddProductRoute: typeof AppHiddenLayoutAddProductRoute AppHiddenLayoutAuthedRoute: typeof AppHiddenLayoutAuthedRouteWithChildren
AppHiddenLayoutAppSettingsRoute: typeof AppHiddenLayoutAppSettingsRoute
AppHiddenLayoutInventoryRoute: typeof AppHiddenLayoutInventoryRoute
AppHiddenLayoutStoragesRoute: typeof AppHiddenLayoutStoragesRoute
AppHiddenLayoutViewProductRoute: typeof AppHiddenLayoutViewProductRoute
AppHiddenLayoutQuickViewProductRoute: typeof AppHiddenLayoutQuickViewProductRoute AppHiddenLayoutQuickViewProductRoute: typeof AppHiddenLayoutQuickViewProductRoute
} }
const AppHiddenLayoutRouteChildren: AppHiddenLayoutRouteChildren = { const AppHiddenLayoutRouteChildren: AppHiddenLayoutRouteChildren = {
AppHiddenLayoutAddProductRoute: AppHiddenLayoutAddProductRoute, AppHiddenLayoutAuthedRoute: AppHiddenLayoutAuthedRouteWithChildren,
AppHiddenLayoutAppSettingsRoute: AppHiddenLayoutAppSettingsRoute,
AppHiddenLayoutInventoryRoute: AppHiddenLayoutInventoryRoute,
AppHiddenLayoutStoragesRoute: AppHiddenLayoutStoragesRoute,
AppHiddenLayoutViewProductRoute: AppHiddenLayoutViewProductRoute,
AppHiddenLayoutQuickViewProductRoute: AppHiddenLayoutQuickViewProductRoute, AppHiddenLayoutQuickViewProductRoute: AppHiddenLayoutQuickViewProductRoute,
} }
@@ -0,0 +1,9 @@
import { createFileRoute, Outlet } from "@tanstack/react-router";
import { verifyLogin } from "../../../utils/api/auth";
export const Route = createFileRoute("/app/_hiddenLayout/_authed")({
beforeLoad: async () => {
await verifyLogin();
},
component: () => <Outlet />,
});
@@ -0,0 +1,10 @@
import { createFileRoute } from "@tanstack/react-router";
import { AddProduct } from "../../../../pages/AddProduct";
export const Route = createFileRoute("/app/_hiddenLayout/_authed/add-product")({
component: RouteComponent,
});
function RouteComponent() {
return <AddProduct />;
}
@@ -0,0 +1,12 @@
import { createFileRoute } from "@tanstack/react-router";
import { Settings } from "../../../../pages/Settings";
export const Route = createFileRoute("/app/_hiddenLayout/_authed/app-settings")(
{
component: RouteComponent,
},
);
function RouteComponent() {
return <Settings />;
}
@@ -0,0 +1,10 @@
import { createFileRoute } from "@tanstack/react-router";
import { InventoryPage } from "../../../../pages/Inventory";
export const Route = createFileRoute("/app/_hiddenLayout/_authed/inventory")({
component: RouteComponent,
});
function RouteComponent() {
return <InventoryPage />;
}
@@ -0,0 +1,10 @@
import { createFileRoute } from "@tanstack/react-router";
import { Storages } from "../../../../pages/Storages";
export const Route = createFileRoute("/app/_hiddenLayout/_authed/storages")({
component: RouteComponent,
});
function RouteComponent() {
return <Storages />;
}
@@ -0,0 +1,17 @@
import { createFileRoute } from "@tanstack/react-router";
import { z } from "zod";
import { ViewProduct } from "../../../../pages/ViewProduct";
export const Route = createFileRoute("/app/_hiddenLayout/_authed/view-product")(
{
validateSearch: z.object({
product: z.string(),
}),
component: RouteComponent,
},
);
function RouteComponent() {
const { product } = Route.useSearch();
return <ViewProduct uuid={product} />;
}
@@ -1,18 +0,0 @@
import { createFileRoute, redirect } from "@tanstack/react-router";
import { isAuthenticated } from "../../../utils/api/auth";
import { AddProduct } from "../../../pages/AddProduct";
export const Route = createFileRoute("/app/_hiddenLayout/add-product")({
beforeLoad: async () => {
if (!(await isAuthenticated())) {
throw redirect({
to: "/login",
});
}
},
component: RouteComponent,
});
function RouteComponent() {
return <AddProduct />;
}
@@ -1,18 +0,0 @@
import { createFileRoute, redirect } from "@tanstack/react-router";
import { isAuthenticated } from "../../../utils/api/auth";
import { Settings } from "../../../pages/Settings";
export const Route = createFileRoute("/app/_hiddenLayout/app-settings")({
beforeLoad: async () => {
if (!(await isAuthenticated())) {
throw redirect({
to: "/login",
});
}
},
component: RouteComponent,
});
function RouteComponent() {
return <Settings />;
}
@@ -1,18 +0,0 @@
import { createFileRoute, redirect } from "@tanstack/react-router";
import { isAuthenticated } from "../../../utils/api/auth";
import { InventoryPage } from "../../../pages/Inventory";
export const Route = createFileRoute("/app/_hiddenLayout/inventory")({
beforeLoad: async () => {
if (!(await isAuthenticated())) {
throw redirect({
to: "/login",
});
}
},
component: RouteComponent,
});
function RouteComponent() {
return <InventoryPage />;
}
@@ -1,18 +0,0 @@
import { createFileRoute, redirect } from "@tanstack/react-router";
import { isAuthenticated } from "../../../utils/api/auth";
import { Storages } from "../../../pages/Storages";
export const Route = createFileRoute("/app/_hiddenLayout/storages")({
beforeLoad: async () => {
if (!(await isAuthenticated())) {
throw redirect({
to: "/login",
});
}
},
component: RouteComponent,
});
function RouteComponent() {
return <Storages />;
}
@@ -1,23 +0,0 @@
import { createFileRoute, redirect } from "@tanstack/react-router";
import { z } from "zod";
import { isAuthenticated } from "../../../utils/api/auth";
import { ViewProduct } from "../../../pages/ViewProduct";
export const Route = createFileRoute("/app/_hiddenLayout/view-product")({
beforeLoad: async () => {
if (!(await isAuthenticated())) {
throw redirect({
to: "/login",
});
}
},
validateSearch: z.object({
product: z.string(),
}),
component: RouteComponent,
});
function RouteComponent() {
const { product } = Route.useSearch();
return <ViewProduct uuid={product} />;
}
+1
View File
@@ -6,6 +6,7 @@ export const Route = createFileRoute("/")({
if (!(await isAuthenticated())) { if (!(await isAuthenticated())) {
throw redirect({ throw redirect({
to: "/login", to: "/login",
search: { loggedOut: true },
}); });
} else { } else {
throw redirect({ throw redirect({
+4
View File
@@ -1,7 +1,11 @@
import { createFileRoute } from "@tanstack/react-router"; import { createFileRoute } from "@tanstack/react-router";
import { LoginCard } from "../components/LoginCard"; import { LoginCard } from "../components/LoginCard";
import { checkLogin } from "../utils/api/auth.ts";
export const Route = createFileRoute("/login")({ export const Route = createFileRoute("/login")({
beforeLoad: async () => {
await checkLogin();
},
component: RouteComponent, component: RouteComponent,
}); });
+31 -18
View File
@@ -1,11 +1,12 @@
import {API_BASE} from "../../config/api.config"; import { API_BASE } from "../../config/api.config";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import type {TFunction} from "i18next"; import type { TFunction } from "i18next";
import {fetchSettings} from "./settings"; import { fetchSettings } from "./settings";
import type {ChangePasswordIntf} from "../../misc/interfaces"; import type { ChangePasswordIntf } from "../../misc/interfaces";
import {createApiError} from "./apiError"; import { createApiError } from "./apiError";
import { redirect } from "@tanstack/react-router";
export async function isAuthenticated() { export const isAuthenticated = async () => {
if (Cookies.get("token")) { if (Cookies.get("token")) {
const result = await fetch(`${API_BASE}/users/verify-token`, { const result = await fetch(`${API_BASE}/users/verify-token`, {
method: "POST", method: "POST",
@@ -23,13 +24,13 @@ export async function isAuthenticated() {
Cookies.remove("token"); Cookies.remove("token");
return false; return false;
} };
export async function signInUser( export const signInUser = async (
username: string, username: string,
password: string, password: string,
t: TFunction, t: TFunction,
) { ) => {
const result = await fetch(`${API_BASE}/users/login`, { const result = await fetch(`${API_BASE}/users/login`, {
method: "POST", method: "POST",
headers: { headers: {
@@ -37,7 +38,7 @@ export async function signInUser(
"Content-Type": "application/json", "Content-Type": "application/json",
Accept: "application/json", Accept: "application/json",
}, },
body: JSON.stringify({username, password}), body: JSON.stringify({ username, password }),
}); });
const response = await result.json(); const response = await result.json();
@@ -49,17 +50,12 @@ export async function signInUser(
Cookies.set("app-name", settings?.data[0].value); Cookies.set("app-name", settings?.data[0].value);
Cookies.set("currency", settings?.data[1].value); Cookies.set("currency", settings?.data[1].value);
return {ok: true as const}; return { ok: true as const };
} }
Cookies.remove("token"); Cookies.remove("token");
throw createApiError(response.code, t(response.code || "unknown-error")); throw createApiError(response.code, t(response.code || "unknown-error"));
} };
export function signOutUser() {
Cookies.remove("token");
return {ok: true as const};
}
export const mutatePassword = async (payload: ChangePasswordIntf) => { export const mutatePassword = async (payload: ChangePasswordIntf) => {
const result = await fetch(`${API_BASE}/users/change-password`, { const result = await fetch(`${API_BASE}/users/change-password`, {
@@ -78,8 +74,25 @@ export const mutatePassword = async (payload: ChangePasswordIntf) => {
const response = await result.json(); const response = await result.json();
if (response.code === "SU005") { if (response.code === "SU005") {
return {code: response.code}; return { code: response.code };
} }
throw createApiError(response.code, "Change password failed"); throw createApiError(response.code, "Change password failed");
}; };
export const verifyLogin = async () => {
if (!(await isAuthenticated())) {
throw redirect({
to: "/login",
search: { loggedOut: true },
});
}
};
export const checkLogin = async () => {
if (await isAuthenticated()) {
throw redirect({
to: "/app/inventory",
});
}
};
-13
View File
@@ -6331,19 +6331,6 @@
"integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==", "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/react-toastify": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.1.0.tgz",
"integrity": "sha512-e9h23x3phN0wbFeB6yovmWp7lobzV4CaCH0LO8nVP6H7Y+3GbcLpIzMm9dJhcp1RXbpyfvjgpfXqO80QAmn7sg==",
"license": "MIT",
"dependencies": {
"clsx": "^2.1.1"
},
"peerDependencies": {
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
}
},
"node_modules/react-transition-group": { "node_modules/react-transition-group": {
"version": "4.4.5", "version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",