feat: add Business Production Cookbook dashboard - #238
feat: add Business Production Cookbook dashboard#238Tarik Skalić (tarikskalic33) wants to merge 2 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
aegisomega | e70a979 | Commit Preview URL Branch Preview URL |
Jul 28 2026, 11:04 AM |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 60cf6f5f18
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "Codex (@codex) review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".
| <aside className={menu ? 'sidebar open' : 'sidebar'}> | ||
| <button className="close" onClick={() => setMenu(false)} aria-label="Close menu"><X/></button> | ||
| <div className="brand"><span><Wheat size={20}/></span><b>batchbook</b></div> | ||
| <nav>{nav.map(([name, Icon]) => <button key={name} className={active === name ? 'active' : ''} onClick={() => { setActive(name); setMenu(false) }}><Icon size={18}/>{name}</button>)}</nav> |
There was a problem hiding this comment.
Render the section selected by the navigation
When a user selects Production, Recipes, Inventory, or another sidebar item, this handler only updates the highlighted button; the main area continues to show the Overview dashboard. The same mismatch occurs through the “View schedule” and “Inventory” shortcuts, leaving the UI claiming a different active section without navigating or changing content.
Useful? React with 👍 / 👎.
| const [query, setQuery] = useState('') | ||
| const [menu, setMenu] = useState(false) | ||
| const [toast, setToast] = useState('') | ||
| const filtered = useMemo(() => batches.filter(b => `${b.product} ${b.id}`.toLowerCase().includes(query.toLowerCase())), [query]) |
There was a problem hiding this comment.
Search all entity types advertised by the input
The header advertises search across products, batches, and orders, but this filter only checks the four production batches. For example, searching for ORD-1084 or Atelier Hotel reports no matching production batches while leaving the matching order unchanged, so order and other non-batch searches cannot work as presented.
Useful? React with 👍 / 👎.
| @@ -0,0 +1,3 @@ | |||
| @import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Manrope:wght@500;600;700&display=swap'); | |||
| :root{font-family:'DM Sans',sans-serif;color:#252722;background:#f5f4ef;font-synthesis:none}*{box-sizing:border-box}body{margin:0}button,input{font:inherit}button{cursor:pointer}.shell{min-height:100vh;display:flex}.sidebar{position:fixed;width:226px;height:100vh;background:#183f36;color:#dce9e3;padding:28px 16px 18px;display:flex;flex-direction:column;z-index:10}.brand{display:flex;align-items:center;gap:10px;padding:0 10px 30px;color:white;font:700 20px Manrope}.brand span{width:31px;height:31px;display:grid;place-items:center;background:#d9b66c;color:#173d34;border-radius:9px}.sidebar nav{display:flex;flex-direction:column;gap:3px}.sidebar nav button,.side-bottom button{border:0;background:transparent;color:#afc3bc;border-radius:8px;padding:10px 12px;display:flex;align-items:center;gap:12px;text-align:left;font-size:14px;font-weight:500}.sidebar nav button:hover,.sidebar nav button.active{background:#28584c;color:white}.sidebar nav button.active{box-shadow:inset 3px 0 #e5bd68}.workspace{margin-top:auto;border-top:1px solid #326056;border-bottom:1px solid #326056;padding:17px 5px;display:flex;gap:9px;align-items:center}.workspace .avatar{width:34px;height:34px;background:#e0b665;color:#25493f;border-radius:50%;display:grid;place-items:center;font-weight:700;font-size:12px}.workspace div:nth-child(2){flex:1}.workspace b,.workspace small{display:block;font-size:12px}.workspace small{color:#88a69d;margin-top:2px}.side-bottom{padding-top:10px;display:flex;flex-direction:column}.close{display:none}main{margin-left:226px;width:calc(100% - 226px)}header{height:68px;background:#fff;border-bottom:1px solid #e6e4db;display:flex;align-items:center;padding:0 34px;gap:18px;position:sticky;top:0;z-index:5}.search{display:flex;align-items:center;color:#92938e;gap:10px;max-width:475px;flex:1}.search input{border:0;outline:0;width:100%;font-size:13px}.search kbd{border:1px solid #deddd7;border-radius:5px;padding:3px 7px;color:#999;background:#f9f9f7;font-size:11px;white-space:nowrap}.icon-btn{position:relative;margin-left:auto;border:0;background:transparent;color:#73756f}.icon-btn i{position:absolute;width:6px;height:6px;background:#d98254;border-radius:50%;right:5px;top:3px}.today{display:flex;gap:8px;align-items:center;padding-left:18px;border-left:1px solid #e6e4dd;font-size:13px;color:#62645e}.menu{display:none;border:0;background:transparent}.content{max-width:1440px;margin:auto;padding:38px 40px 60px}.welcome{display:flex;align-items:flex-end;justify-content:space-between}.welcome p{font-size:10px;letter-spacing:1.6px;font-weight:700;color:#99988e;margin:0 0 9px}.welcome h1{font:700 27px Manrope;margin:0 0 6px;color:#22251f}.welcome span{color:#777871;font-size:14px}.primary{border:0;background:#225246;color:white;border-radius:8px;padding:11px 16px;display:flex;align-items:center;gap:8px;font-weight:600;font-size:13px;box-shadow:0 3px 8px #173e2c22}.metrics{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin:29px 0 17px}.metric,.card{background:#fff;border:1px solid #e4e2d9;border-radius:10px}.metric{padding:18px 20px}.metric-label{color:#777870;font-size:12px;display:flex;justify-content:space-between}.metric-label svg{color:#bbb}.metric strong{display:block;font:700 25px Manrope;margin-top:11px}.metric p{font-size:11px;color:#898a83;margin:5px 0 0}.metric p.good{color:#43806e}.grid-main{display:grid;grid-template-columns:1.55fr 1fr;gap:17px}.card-head{padding:19px 21px 15px;display:flex;justify-content:space-between;align-items:center}.card-head h2{font:700 15px Manrope;margin:0 0 4px}.card-head p{margin:0;color:#92938c;font-size:11px}.card-head button{border:0;background:transparent;color:#356b5b;font-weight:600;font-size:11px;display:flex;align-items:center;gap:3px}.batch-list{padding:0 21px 10px}.batch{display:flex;min-height:70px}.time{width:64px;font-weight:600;font-size:12px;padding-top:13px;position:relative}.time span{position:absolute;right:12px;top:18px;width:9px;height:9px;border:2px solid white;border-radius:50%;background:#adb1aa;box-shadow:0 0 0 1px #d5d7d0}.time span.blue{background:#497b9a}.time span.green{background:#559f76}.batch-info{border-left:1px solid #e3e4de;flex:1;display:grid;grid-template-columns:1fr 110px 90px 25px;align-items:start;padding:10px 0 10px 16px;gap:10px}.batch-info b,.batch-info small,.stock-name b,.stock-name small,.stock-qty b,.stock-qty small,.order b,.order small{display:block}.batch-info b{font-size:12px}.batch-info small,.stock-name small,.stock-qty small,.order small{font-size:10px;color:#96978f;margin-top:4px}.badge{justify-self:start;border-radius:20px;padding:5px 9px;font-size:9px;font-weight:700;background:#f0f1ed;color:#767b74;white-space:nowrap}.badge.blue{background:#e8f1f5;color:#3f718b}.badge.green{background:#e5f3ea;color:#3f7958}.badge.amber{background:#f8f0dd;color:#957035}.bar{height:4px;background:#eee;border-radius:5px;margin-top:10px}.bar i,.stockbar i{display:block;height:100%;border-radius:5px;background:#4e8d74}.batch-info>button{border:0;background:transparent;color:#aaa;padding:3px}.batch-info>button svg{width:16px}.empty{padding:35px;text-align:center;color:#999;font-size:13px}.stock{padding-bottom:15px}.stock-row{display:grid;grid-template-columns:38px 1fr auto;gap:10px;align-items:center;padding:11px 21px}.stock-icon,.order-icon{width:34px;height:34px;border-radius:8px;background:#f5eee2;color:#ae7d45;display:grid;place-items:center}.stock-name b,.stock-qty b{font-size:11px}.stock-qty{text-align:right}.stockbar{grid-column:2/4;height:4px;background:#efece3;border-radius:4px}.stockbar i{background:#d59462}.restock{margin:12px 21px 0;width:calc(100% - 42px);border:1px solid #d9dbd5;background:#fff;color:#316756;border-radius:7px;padding:9px;display:flex;align-items:center;justify-content:center;gap:6px;font-size:11px;font-weight:600}.lower{display:grid;grid-template-columns:1.55fr 1fr;gap:17px;margin-top:17px}.orders{padding-bottom:8px}.order{display:grid;grid-template-columns:38px 1fr 120px 130px;gap:10px;align-items:center;padding:11px 21px;border-top:1px solid #efeee8}.order b{font-size:11px}.order-icon{background:#edf2ee;color:#487963}.order-icon svg{width:17px}.insight{border-radius:10px;background:#e5eee8;border:1px solid #cfddd4;padding:24px;display:flex;gap:14px;color:#265547}.insight>svg{flex:none}.insight span{font-size:9px;font-weight:700;letter-spacing:1.2px}.insight h3{font:700 15px Manrope;margin:9px 0 7px;color:#23463d}.insight p{font-size:11px;line-height:1.55;color:#537069}.insight button{border:0;background:transparent;padding:6px 0;color:#285d4e;font-weight:700;font-size:10px;display:flex;gap:3px;align-items:center}.toast{position:fixed;right:25px;bottom:25px;background:#173f35;color:white;padding:13px 18px;border-radius:9px;display:flex;gap:9px;align-items:center;font-size:13px;box-shadow:0 8px 30px #0003;z-index:30} | |||
| @media(max-width:1050px){.metrics{grid-template-columns:repeat(2,1fr)}.grid-main,.lower{grid-template-columns:1fr}.stock{min-height:0}}@media(max-width:720px){.sidebar{transform:translateX(-100%);transition:.2s}.sidebar.open{transform:none;box-shadow:20px 0 50px #0004}.close{display:block;position:absolute;right:10px;top:10px;border:0;background:transparent;color:white}.close svg{width:20px}main{margin-left:0;width:100%}.menu{display:block}.content{padding:25px 18px}.today{display:none}.welcome{align-items:flex-start;gap:20px}.welcome .primary{font-size:0;padding:11px}.welcome .primary svg{margin:0}.metrics{grid-template-columns:1fr 1fr}.batch-info{grid-template-columns:1fr auto 20px}.batch-info .bar{display:none}.order{grid-template-columns:38px 1fr auto}.order>div:nth-child(3){display:none}.order .badge{grid-column:2}.search kbd{display:none}}@media(max-width:470px){.metrics{grid-template-columns:1fr}.batch-info .badge{display:none}.batch-info{grid-template-columns:1fr 20px}.welcome h1{font-size:23px}header{padding:0 16px}} | |||
There was a problem hiding this comment.
Allow the fixed sidebar to scroll on short viewports
On short browser windows and phone landscape layouts, the fixed 100vh sidebar contains more navigation and footer content than its available height but has no vertical overflow handling. Lower entries, workspace controls, Settings, and Help can consequently overflow or overlap while remaining unreachable because the page scrolls behind the fixed sidebar; make the sidebar or its navigation region vertically scrollable.
Useful? React with 👍 / 👎.
| { name: 'Cultured butter', meta: 'MAT-0018 · Chilled', left: '6.2 kg', min: '10 kg', pct: 35 }, | ||
| { name: 'Almond flour', meta: 'MAT-0031 · Dry store', left: '3.8 kg', min: '8 kg', pct: 25 }, | ||
| { name: 'Berry mix', meta: 'MAT-0044 · Frozen', left: '4.1 kg', min: '6 kg', pct: 45 }, |
There was a problem hiding this comment.
Derive stock bars from the displayed quantities
Each stock row renders pct directly as the bar width, but these percentages disagree with the adjacent remaining and minimum quantities: for example, 6.2 kg of 10 kg is shown as 35% rather than 62%, and 3.8 kg of 8 kg is shown as 25% rather than 47.5%. This makes the graphical stock level materially misrepresent the values operators use to assess shortages; calculate the width from left / min or label the bar as a different measure.
Useful? React with 👍 / 👎.
PR Summary by QodoAdd standalone Business Production Cookbook dashboard (React/Vite scaffold)
AI Description
Diagram
High-Level Assessment
Files changed (12)
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
11 rules 1. Navigation never changes content
|
| <aside className={menu ? 'sidebar open' : 'sidebar'}> | ||
| <button className="close" onClick={() => setMenu(false)} aria-label="Close menu"><X/></button> | ||
| <div className="brand"><span><Wheat size={20}/></span><b>batchbook</b></div> | ||
| <nav>{nav.map(([name, Icon]) => <button key={name} className={active === name ? 'active' : ''} onClick={() => { setActive(name); setMenu(false) }}><Icon size={18}/>{name}</button>)}</nav> |
There was a problem hiding this comment.
2. Navigation never changes content 🐞 Bug ≡ Correctness
Navigation handlers only update the active styling while the Overview dashboard is rendered unconditionally. Selecting Production, Inventory, Orders, or Reports therefore highlights a destination without opening it.
Agent Prompt
## Issue description
Sidebar and dashboard navigation controls only change the selected styling; they never render or route to the selected destination. Implement actual navigation, or disable/remove destinations until their views exist.
## Issue Context
The `active` state is currently consumed only by the sidebar class name, while the main dashboard is always rendered.
## Fix Focus Areas
- production-cookbook/src/App.tsx[28-58]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| const [query, setQuery] = useState('') | ||
| const [menu, setMenu] = useState(false) | ||
| const [toast, setToast] = useState('') | ||
| const filtered = useMemo(() => batches.filter(b => `${b.product} ${b.id}`.toLowerCase().includes(query.toLowerCase())), [query]) |
There was a problem hiding this comment.
3. Search ignores advertised records 🐞 Bug ≡ Correctness
The header advertises searching products, batches, and orders, but filtered searches only batch product names and IDs. Searching a visible order such as ORD-1084 empties the production list without locating or filtering that matching order.
Agent Prompt
## Issue description
The global search advertises record types that its filtering implementation does not search. Either implement unified results/filtering for the advertised entities or restrict the input label and placement to production batches.
## Issue Context
Orders are rendered separately from the only array searched by `filtered`.
## Fix Focus Areas
- production-cookbook/src/App.tsx[10-55]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| const [menu, setMenu] = useState(false) | ||
| const [toast, setToast] = useState('') | ||
| const filtered = useMemo(() => batches.filter(b => `${b.product} ${b.id}`.toLowerCase().includes(query.toLowerCase())), [query]) | ||
| const notify = (message: string) => { setToast(message); window.setTimeout(() => setToast(''), 2400) } |
There was a problem hiding this comment.
4. Older timer clears newer toast 🐞 Bug ☼ Reliability
Each notify call schedules an unconditional clear without cancelling the previous timeout. When two actions occur within 2.4 seconds, the first timer removes the newer notification before its intended display period ends.
Agent Prompt
## Issue description
Independent notification timers can clear messages created by later actions. Retain the active timeout in a ref, cancel it before scheduling a replacement, and clean it up when the component unmounts.
## Issue Context
Both production-batch and purchase-order actions invoke the same timer-based notification function.
## Fix Focus Areas
- production-cookbook/src/App.tsx[27-33]
- production-cookbook/src/App.tsx[46-52]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| @@ -0,0 +1,3 @@ | |||
| @import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Manrope:wght@500;600;700&display=swap'); | |||
| :root{font-family:'DM Sans',sans-serif;color:#252722;background:#f5f4ef;font-synthesis:none}*{box-sizing:border-box}body{margin:0}button,input{font:inherit}button{cursor:pointer}.shell{min-height:100vh;display:flex}.sidebar{position:fixed;width:226px;height:100vh;background:#183f36;color:#dce9e3;padding:28px 16px 18px;display:flex;flex-direction:column;z-index:10}.brand{display:flex;align-items:center;gap:10px;padding:0 10px 30px;color:white;font:700 20px Manrope}.brand span{width:31px;height:31px;display:grid;place-items:center;background:#d9b66c;color:#173d34;border-radius:9px}.sidebar nav{display:flex;flex-direction:column;gap:3px}.sidebar nav button,.side-bottom button{border:0;background:transparent;color:#afc3bc;border-radius:8px;padding:10px 12px;display:flex;align-items:center;gap:12px;text-align:left;font-size:14px;font-weight:500}.sidebar nav button:hover,.sidebar nav button.active{background:#28584c;color:white}.sidebar nav button.active{box-shadow:inset 3px 0 #e5bd68}.workspace{margin-top:auto;border-top:1px solid #326056;border-bottom:1px solid #326056;padding:17px 5px;display:flex;gap:9px;align-items:center}.workspace .avatar{width:34px;height:34px;background:#e0b665;color:#25493f;border-radius:50%;display:grid;place-items:center;font-weight:700;font-size:12px}.workspace div:nth-child(2){flex:1}.workspace b,.workspace small{display:block;font-size:12px}.workspace small{color:#88a69d;margin-top:2px}.side-bottom{padding-top:10px;display:flex;flex-direction:column}.close{display:none}main{margin-left:226px;width:calc(100% - 226px)}header{height:68px;background:#fff;border-bottom:1px solid #e6e4db;display:flex;align-items:center;padding:0 34px;gap:18px;position:sticky;top:0;z-index:5}.search{display:flex;align-items:center;color:#92938e;gap:10px;max-width:475px;flex:1}.search input{border:0;outline:0;width:100%;font-size:13px}.search kbd{border:1px solid #deddd7;border-radius:5px;padding:3px 7px;color:#999;background:#f9f9f7;font-size:11px;white-space:nowrap}.icon-btn{position:relative;margin-left:auto;border:0;background:transparent;color:#73756f}.icon-btn i{position:absolute;width:6px;height:6px;background:#d98254;border-radius:50%;right:5px;top:3px}.today{display:flex;gap:8px;align-items:center;padding-left:18px;border-left:1px solid #e6e4dd;font-size:13px;color:#62645e}.menu{display:none;border:0;background:transparent}.content{max-width:1440px;margin:auto;padding:38px 40px 60px}.welcome{display:flex;align-items:flex-end;justify-content:space-between}.welcome p{font-size:10px;letter-spacing:1.6px;font-weight:700;color:#99988e;margin:0 0 9px}.welcome h1{font:700 27px Manrope;margin:0 0 6px;color:#22251f}.welcome span{color:#777871;font-size:14px}.primary{border:0;background:#225246;color:white;border-radius:8px;padding:11px 16px;display:flex;align-items:center;gap:8px;font-weight:600;font-size:13px;box-shadow:0 3px 8px #173e2c22}.metrics{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin:29px 0 17px}.metric,.card{background:#fff;border:1px solid #e4e2d9;border-radius:10px}.metric{padding:18px 20px}.metric-label{color:#777870;font-size:12px;display:flex;justify-content:space-between}.metric-label svg{color:#bbb}.metric strong{display:block;font:700 25px Manrope;margin-top:11px}.metric p{font-size:11px;color:#898a83;margin:5px 0 0}.metric p.good{color:#43806e}.grid-main{display:grid;grid-template-columns:1.55fr 1fr;gap:17px}.card-head{padding:19px 21px 15px;display:flex;justify-content:space-between;align-items:center}.card-head h2{font:700 15px Manrope;margin:0 0 4px}.card-head p{margin:0;color:#92938c;font-size:11px}.card-head button{border:0;background:transparent;color:#356b5b;font-weight:600;font-size:11px;display:flex;align-items:center;gap:3px}.batch-list{padding:0 21px 10px}.batch{display:flex;min-height:70px}.time{width:64px;font-weight:600;font-size:12px;padding-top:13px;position:relative}.time span{position:absolute;right:12px;top:18px;width:9px;height:9px;border:2px solid white;border-radius:50%;background:#adb1aa;box-shadow:0 0 0 1px #d5d7d0}.time span.blue{background:#497b9a}.time span.green{background:#559f76}.batch-info{border-left:1px solid #e3e4de;flex:1;display:grid;grid-template-columns:1fr 110px 90px 25px;align-items:start;padding:10px 0 10px 16px;gap:10px}.batch-info b,.batch-info small,.stock-name b,.stock-name small,.stock-qty b,.stock-qty small,.order b,.order small{display:block}.batch-info b{font-size:12px}.batch-info small,.stock-name small,.stock-qty small,.order small{font-size:10px;color:#96978f;margin-top:4px}.badge{justify-self:start;border-radius:20px;padding:5px 9px;font-size:9px;font-weight:700;background:#f0f1ed;color:#767b74;white-space:nowrap}.badge.blue{background:#e8f1f5;color:#3f718b}.badge.green{background:#e5f3ea;color:#3f7958}.badge.amber{background:#f8f0dd;color:#957035}.bar{height:4px;background:#eee;border-radius:5px;margin-top:10px}.bar i,.stockbar i{display:block;height:100%;border-radius:5px;background:#4e8d74}.batch-info>button{border:0;background:transparent;color:#aaa;padding:3px}.batch-info>button svg{width:16px}.empty{padding:35px;text-align:center;color:#999;font-size:13px}.stock{padding-bottom:15px}.stock-row{display:grid;grid-template-columns:38px 1fr auto;gap:10px;align-items:center;padding:11px 21px}.stock-icon,.order-icon{width:34px;height:34px;border-radius:8px;background:#f5eee2;color:#ae7d45;display:grid;place-items:center}.stock-name b,.stock-qty b{font-size:11px}.stock-qty{text-align:right}.stockbar{grid-column:2/4;height:4px;background:#efece3;border-radius:4px}.stockbar i{background:#d59462}.restock{margin:12px 21px 0;width:calc(100% - 42px);border:1px solid #d9dbd5;background:#fff;color:#316756;border-radius:7px;padding:9px;display:flex;align-items:center;justify-content:center;gap:6px;font-size:11px;font-weight:600}.lower{display:grid;grid-template-columns:1.55fr 1fr;gap:17px;margin-top:17px}.orders{padding-bottom:8px}.order{display:grid;grid-template-columns:38px 1fr 120px 130px;gap:10px;align-items:center;padding:11px 21px;border-top:1px solid #efeee8}.order b{font-size:11px}.order-icon{background:#edf2ee;color:#487963}.order-icon svg{width:17px}.insight{border-radius:10px;background:#e5eee8;border:1px solid #cfddd4;padding:24px;display:flex;gap:14px;color:#265547}.insight>svg{flex:none}.insight span{font-size:9px;font-weight:700;letter-spacing:1.2px}.insight h3{font:700 15px Manrope;margin:9px 0 7px;color:#23463d}.insight p{font-size:11px;line-height:1.55;color:#537069}.insight button{border:0;background:transparent;padding:6px 0;color:#285d4e;font-weight:700;font-size:10px;display:flex;gap:3px;align-items:center}.toast{position:fixed;right:25px;bottom:25px;background:#173f35;color:white;padding:13px 18px;border-radius:9px;display:flex;gap:9px;align-items:center;font-size:13px;box-shadow:0 8px 30px #0003;z-index:30} | |||
There was a problem hiding this comment.
5. Short viewports hide navigation 🐞 Bug ≡ Correctness
The sidebar is fixed to 100vh but has no vertical overflow handling despite containing ten navigation rows and several additional controls. On sufficiently short viewports, such as mobile landscape, lower controls extend below the viewport and cannot be reached through sidebar scrolling.
Agent Prompt
## Issue description
The fixed-height sidebar can contain more content than short viewports can display. Add vertical overflow behavior to the sidebar or constrain its internal sections so every navigation and utility control remains reachable.
## Issue Context
The sidebar always includes the brand, ten navigation items, workspace selector, Settings, and Help controls.
## Fix Focus Areas
- production-cookbook/src/index.css[2-3]
- production-cookbook/src/App.tsx[36-42]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
Code review by qodo was updated up to the latest commit e70a979 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e70a9794d8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "Codex (@codex) review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".
| <div className="side-bottom"><button><Settings size={18}/>Settings</button><button><HelpCircle size={18}/>Help & support</button></div> | ||
| </aside> | ||
| <main> | ||
| <header><button className="menu" onClick={() => setMenu(true)} aria-label="Open menu"><Menu/></button><div className="search"><Search size={18}/><input value={query} onChange={e => setQuery(e.target.value)} placeholder="Search products, batches, orders…"/><kbd>⌘ K</kbd></div><button className="icon-btn" aria-label="Notifications"><Bell size={19}/><i/></button><div className="today"><CalendarDays size={18}/><span>Mon, 28 July</span></div></header> |
There was a problem hiding this comment.
Derive the displayed business date dynamically
When this dashboard is opened on any business day other than Monday, 28 July, the header still advertises that fixed date while the rest of the page frames batches, KPIs, and orders as “today”/“tomorrow”. That can make operators act on a production overview that appears current but is stamped with a stale day; derive this label from the current business date or the same schedule data that drives the dashboard.
Useful? React with 👍 / 👎.
Motivation
Description
production-cookbookapp containing a Vite/React TypeScript project withpackage.json,vite.config.ts,tsconfig.*, and a lightweightindex.html.src/App.tsxplussrc/main.tsx,src/index.css, and asrc/vite-env.d.tshelper; the UI models batches, low-stock materials, orders, KPIs, responsive navigation, mobile layout, and simple interactive notifications using local mock data..gitignorein the new package to excludedistand*.tsbuildinfo.Testing
npm installinproduction-cookbookwhich completed and populated dependencies successfully.npm run buildwhich initially failed with aTS2882side-effect CSS import type error and was resolved by addingsrc/vite-env.d.ts, after whichtsc -b && vite buildcompleted and produced adistbundle.Codex Task