Compare commits

...
8 Commits
Author SHA1 Message Date
Hamed d5a7ed8092 feat: add landing page device images and fix machine branding
Build & Deploy (develop) / build-and-deploy (push) Successful in 1m41s
2026-09-14 10:39:58 +03:30
Hamed ba464e8345 feat: add landing page device images and fix machine branding
Build & Deploy (develop) / build-and-deploy (push) Successful in 1m40s
2026-09-14 10:19:47 +03:30
Hamed 7c73714d56 feat: add landing page device images and fix machine branding
Build & Deploy (develop) / build-and-deploy (push) Successful in 1m38s
2026-09-14 10:09:21 +03:30
Hamed fe86b58012 update
Build & Deploy (develop) / build-and-deploy (push) Successful in 1m44s
2026-09-14 08:36:22 +03:30
Hamed c4d9351e91 update
Build & Deploy (develop) / build-and-deploy (push) Successful in 1m39s
2026-09-12 07:43:21 +02:00
Hamed 7e7ebc88b6 initial new branch 2026-09-08 11:22:59 +03:30
Hamed 107413069c minor changes
Build & Deploy (develop) / build-and-deploy (push) Successful in 1m42s
2026-09-08 11:05:18 +03:30
Ryan f9915e4f8c fix:fixed vending price
Build & Deploy (develop) / build-and-deploy (push) Successful in 1m41s
2026-09-07 09:52:41 +03:30
10 changed files with 154 additions and 91 deletions
+6 -2
View File
@@ -33,9 +33,11 @@ jobs:
docker build -t robot-market:${{ steps.vars.outputs.sha }} . docker build -t robot-market:${{ steps.vars.outputs.sha }} .
- name: Save previous tag for rollback - name: Save previous tag for rollback
id: backup
run: | run: |
if [ -f /opt/robot-market-front/.env ]; then if [ -f /opt/robot-market-front/.env ]; then
cp /opt/robot-market-front/.env /opt/robot-market-front/.env.previous cp /opt/robot-market-front/.env /opt/robot-market-front/.env.previous
echo "available=true" >> "$GITHUB_OUTPUT"
fi fi
- name: Point compose at this build - name: Point compose at this build
@@ -43,12 +45,14 @@ jobs:
echo "IMAGE_TAG=${{ steps.vars.outputs.sha }}" > /opt/robot-market-front/.env echo "IMAGE_TAG=${{ steps.vars.outputs.sha }}" > /opt/robot-market-front/.env
- name: Deploy via compose - name: Deploy via compose
id: deploy
run: | run: |
docker compose --env-file /opt/robot-market-front/.env \ docker compose --env-file /opt/robot-market-front/.env \
-f /opt/robot-market-front/docker-compose.yml \ -f /opt/robot-market-front/docker-compose.yml \
up -d --force-recreate up -d --force-recreate
- name: Health check (retries for ~30s) - name: Health check (retries for ~30s)
id: health
run: | run: |
for i in $(seq 1 15); do for i in $(seq 1 15); do
if docker exec robot-market node -e " if docker exec robot-market node -e "
@@ -65,8 +69,8 @@ jobs:
echo "Health check failed after 30s" echo "Health check failed after 30s"
exit 1 exit 1
- name: Roll back to previous version on failed health check - name: Roll back after deployment or health check failure
if: failure() if: ${{ failure() && steps.backup.outputs.available == 'true' && (steps.deploy.outcome == 'failure' || steps.health.outcome == 'failure') }}
run: | run: |
if [ -f /opt/robot-market-front/.env.previous ]; then if [ -f /opt/robot-market-front/.env.previous ]; then
cp /opt/robot-market-front/.env.previous /opt/robot-market-front/.env cp /opt/robot-market-front/.env.previous /opt/robot-market-front/.env
+3
View File
@@ -14,6 +14,9 @@
<Item> <Item>
<option name="path" value=".gitea/workflows/test.yml" /> <option name="path" value=".gitea/workflows/test.yml" />
</Item> </Item>
<Item>
<option name="path" value=".gitea/workflows/develop.yml" />
</Item>
</list> </list>
</option> </option>
</SchemaInfo> </SchemaInfo>
+105 -55
View File
@@ -4,9 +4,9 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="bb7b50a5-be9c-4cd7-a05b-979f0e91b173" name="Changes" comment="initial new branch"> <list default="true" id="bb7b50a5-be9c-4cd7-a05b-979f0e91b173" name="Changes" comment="feat: add landing page device images and fix machine branding">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/data/content.js" beforeDir="false" afterPath="$PROJECT_DIR$/data/content.js" afterDir="false" /> <change beforePath="$PROJECT_DIR$/public/images/machine-slide-2.webp" beforeDir="false" afterPath="$PROJECT_DIR$/public/images/machine-slide-2.webp" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -28,61 +28,61 @@
</component> </component>
<component name="NextEditCompletionFeaturesState"> <component name="NextEditCompletionFeaturesState">
<decayedCancelled> <decayedCancelled>
<entry key="MS100" value="1.7659734554897204" /> <entry key="MS100" value="1.0105021478132723" />
<entry key="MS500" value="2.6200917385797573" /> <entry key="MS500" value="1.6326904583013002" />
<entry key="S2" value="2.895672466750576" /> <entry key="S2" value="3.200495115489667" />
<entry key="S5" value="2.9711768722246337" /> <entry key="S5" value="4.148160592733714" />
<entry key="S10" value="3.095911797960576" /> <entry key="S10" value="4.983360398199462" />
<entry key="S30" value="3.6130929483281937" /> <entry key="S30" value="7.2170837140275825" />
<entry key="S60" value="4.862542006443887" /> <entry key="S60" value="9.732495501143132" />
<entry key="M2" value="8.222118193057797" /> <entry key="M2" value="14.025681297470134" />
<entry key="M5" value="14.352669475563026" /> <entry key="M5" value="22.17637857625762" />
<entry key="M10" value="18.025488407782152" /> <entry key="M10" value="27.702751951097298" />
<entry key="M15" value="19.665360290707866" /> <entry key="M15" value="30.22928327611057" />
<entry key="M30" value="22.62190726116564" /> <entry key="M30" value="34.21976380295617" />
<entry key="H1" value="26.416500535541072" /> <entry key="H1" value="38.60682034968035" />
<entry key="H2" value="30.051114228090462" /> <entry key="H2" value="42.59562362296086" />
<entry key="H4" value="32.65287419479587" /> <entry key="H4" value="45.40713861912438" />
<entry key="D1" value="35.38129255958758" /> <entry key="D1" value="48.33720180411775" />
<entry key="W1" value="35.9099877286286" /> <entry key="W1" value="48.90360237164015" />
</decayedCancelled> </decayedCancelled>
<decayedSelected> <decayedSelected>
<entry key="MS100" value="0.0" /> <entry key="MS100" value="0.0" />
<entry key="MS500" value="1.5499348360687339E-164" /> <entry key="MS500" value="8.86528819923573E-248" />
<entry key="S2" value="1.1157794535925266E-41" /> <entry key="S2" value="1.7255327824639203E-62" />
<entry key="S5" value="4.1594062872493325E-17" /> <entry key="S5" value="1.9713751865934254E-25" />
<entry key="S10" value="6.449345925944224E-9" /> <entry key="S10" value="4.440017101986686E-13" />
<entry key="S30" value="0.0018613950614188026" /> <entry key="S30" value="7.628893420815487E-5" />
<entry key="S60" value="0.043143887880194604" /> <entry key="S60" value="0.008734353680047248" />
<entry key="M2" value="0.20771106826597993" /> <entry key="M2" value="0.09345776415069663" />
<entry key="M5" value="0.533315069904893" /> <entry key="M5" value="0.387477201784943" />
<entry key="M10" value="0.7302842391185045" /> <entry key="M10" value="0.6224766676630884" />
<entry key="M15" value="0.8109510091490459" /> <entry key="M15" value="0.7290355699678522" />
<entry key="M30" value="0.9005281834285062" /> <entry key="M30" value="0.8538357980126227" />
<entry key="H1" value="0.9489616343290734" /> <entry key="H1" value="0.9240323576653702" />
<entry key="H2" value="0.9741466184969663" /> <entry key="H2" value="0.9612660181580177" />
<entry key="H4" value="0.986988661787442" /> <entry key="H4" value="0.9804417464378067" />
<entry key="D1" value="0.9978195926881375" /> <entry key="D1" value="0.9967134048485689" />
<entry key="W1" value="0.9996882217756649" /> <entry key="W1" value="0.9995298237292167" />
</decayedSelected> </decayedSelected>
<decayedShown> <decayedShown>
<entry key="MS100" value="1.6363299214720612" /> <entry key="MS100" value="0.01712637149186048" />
<entry key="MS500" value="2.580440430635064" /> <entry key="MS500" value="0.9540168467150943" />
<entry key="S2" value="2.884654206650678" /> <entry key="S2" value="2.9136793264313505" />
<entry key="S5" value="2.9666305108034594" /> <entry key="S5" value="4.013649896020289" />
<entry key="S10" value="3.0934710562664876" /> <entry key="S10" value="4.909460420460746" />
<entry key="S30" value="3.6138341741583195" /> <entry key="S30" value="7.187579804050971" />
<entry key="S60" value="4.903918162005831" /> <entry key="S60" value="9.723843431274007" />
<entry key="M2" value="8.426649355082025" /> <entry key="M2" value="14.107987700307802" />
<entry key="M5" value="14.882896956006677" /> <entry key="M5" value="22.55725525698723" />
<entry key="M10" value="18.75367770497998" /> <entry key="M10" value="28.321163439518607" />
<entry key="M15" value="20.474761353109788" /> <entry key="M15" value="30.955381308867647" />
<entry key="M30" value="23.521564444287325" /> <entry key="M30" value="35.07198888146704" />
<entry key="H1" value="27.364990222969524" /> <entry key="H1" value="39.52999740754272" />
<entry key="H2" value="31.025011433737856" /> <entry key="H2" value="43.55644480884343" />
<entry key="H4" value="33.639733831212105" /> <entry key="H4" value="46.38735262517173" />
<entry key="D1" value="36.37908993480534" /> <entry key="D1" value="49.33387639135037" />
<entry key="W1" value="36.90967275725512" /> <entry key="W1" value="49.903126627030524" />
</decayedShown> </decayedShown>
</component> </component>
<component name="ProjectColorInfo">{ <component name="ProjectColorInfo">{
@@ -103,12 +103,14 @@
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;, &quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
&quot;RunOnceActivity.typescript.service.memoryLimit.init&quot;: &quot;true&quot;, &quot;RunOnceActivity.typescript.service.memoryLimit.init&quot;: &quot;true&quot;,
&quot;codeWithMe.voiceChat.enabledByDefault&quot;: &quot;false&quot;, &quot;codeWithMe.voiceChat.enabledByDefault&quot;: &quot;false&quot;,
&quot;com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1&quot;: &quot;true&quot;,
&quot;git-widget-placeholder&quot;: &quot;develop&quot;, &quot;git-widget-placeholder&quot;: &quot;develop&quot;,
&quot;javascript.nodejs.core.library.configured.version&quot;: &quot;24.20.0&quot;, &quot;javascript.nodejs.core.library.configured.version&quot;: &quot;24.20.0&quot;,
&quot;javascript.nodejs.core.library.typings.version&quot;: &quot;24.13.3&quot;, &quot;javascript.nodejs.core.library.typings.version&quot;: &quot;24.13.3&quot;,
&quot;javascript.preferred.runtime.type.id&quot;: &quot;node&quot;, &quot;javascript.preferred.runtime.type.id&quot;: &quot;node&quot;,
&quot;js.debugger.nextJs.config.created.client&quot;: &quot;true&quot;, &quot;js.debugger.nextJs.config.created.client&quot;: &quot;true&quot;,
&quot;js.debugger.nextJs.config.created.server&quot;: &quot;true&quot;, &quot;js.debugger.nextJs.config.created.server&quot;: &quot;true&quot;,
&quot;junie.onboarding.icon.badge.shown&quot;: &quot;true&quot;,
&quot;kronk.content.tree.expanded.paths&quot;: &quot;&quot;, &quot;kronk.content.tree.expanded.paths&quot;: &quot;&quot;,
&quot;last_opened_file_path&quot;: &quot;/home/hamed/Documents/Projects/GItLabRepo/device_web&quot;, &quot;last_opened_file_path&quot;: &quot;/home/hamed/Documents/Projects/GItLabRepo/device_web&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;, &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
@@ -117,6 +119,7 @@
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;, &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;, &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;editor.preferences.fonts.default&quot;, &quot;settings.editor.selected.configurable&quot;: &quot;editor.preferences.fonts.default&quot;,
&quot;to.speed.mode.migration.done&quot;: &quot;true&quot;,
&quot;ts.external.directory.path&quot;: &quot;C:\\Program Files\\JetBrains\\WebStorm 2026.1.1\\plugins\\javascript-plugin\\jsLanguageServicesImpl\\external&quot;, &quot;ts.external.directory.path&quot;: &quot;C:\\Program Files\\JetBrains\\WebStorm 2026.1.1\\plugins\\javascript-plugin\\jsLanguageServicesImpl\\external&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot; &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
} }
@@ -188,6 +191,20 @@
<workItem from="1788592387411" duration="8000" /> <workItem from="1788592387411" duration="8000" />
<workItem from="1788592424522" duration="13793000" /> <workItem from="1788592424522" duration="13793000" />
<workItem from="1788670304118" duration="1889000" /> <workItem from="1788670304118" duration="1889000" />
<workItem from="1788772211468" duration="3288000" />
<workItem from="1788845304938" duration="5986000" />
<workItem from="1789189667293" duration="1409000" />
<workItem from="1789191385769" duration="3038000" />
<workItem from="1789200888982" duration="408000" />
<workItem from="1789202103910" duration="646000" />
<workItem from="1789202776318" duration="599000" />
<workItem from="1789207496509" duration="153000" />
<workItem from="1789278993260" duration="734000" />
<workItem from="1789360783891" duration="48000" />
<workItem from="1789361888102" duration="68000" />
<workItem from="1789362025574" duration="23000" />
<workItem from="1789362137185" duration="377000" />
<workItem from="1789362644534" duration="4681000" />
</task> </task>
<task id="LOCAL-00001" summary="update"> <task id="LOCAL-00001" summary="update">
<option name="closed" value="true" /> <option name="closed" value="true" />
@@ -413,7 +430,39 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1788682678051</updated> <updated>1788682678051</updated>
</task> </task>
<option name="localTasksCounter" value="29" /> <task id="LOCAL-00029" summary="update">
<option name="closed" value="true" />
<created>1789191804591</created>
<option name="number" value="00029" />
<option name="presentableId" value="LOCAL-00029" />
<option name="project" value="LOCAL" />
<updated>1789191804591</updated>
</task>
<task id="LOCAL-00030" summary="update">
<option name="closed" value="true" />
<created>1789362384351</created>
<option name="number" value="00030" />
<option name="presentableId" value="LOCAL-00030" />
<option name="project" value="LOCAL" />
<updated>1789362384351</updated>
</task>
<task id="LOCAL-00031" summary="feat: add landing page device images and fix machine branding">
<option name="closed" value="true" />
<created>1789367962553</created>
<option name="number" value="00031" />
<option name="presentableId" value="LOCAL-00031" />
<option name="project" value="LOCAL" />
<updated>1789367962553</updated>
</task>
<task id="LOCAL-00032" summary="feat: add landing page device images and fix machine branding">
<option name="closed" value="true" />
<created>1789368598921</created>
<option name="number" value="00032" />
<option name="presentableId" value="LOCAL-00032" />
<option name="project" value="LOCAL" />
<updated>1789368598921</updated>
</task>
<option name="localTasksCounter" value="33" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@@ -424,10 +473,11 @@
</component> </component>
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<MESSAGE value="ui : change the position of header in Hero Section" /> <MESSAGE value="ui : change the position of header in Hero Section" />
<MESSAGE value="update" />
<MESSAGE value="feat:dockerized &amp; test actions add" /> <MESSAGE value="feat:dockerized &amp; test actions add" />
<MESSAGE value="feat:dockerized &amp; test actions added" /> <MESSAGE value="feat:dockerized &amp; test actions added" />
<MESSAGE value="initial new branch" /> <MESSAGE value="initial new branch" />
<option name="LAST_COMMIT_MESSAGE" value="initial new branch" /> <MESSAGE value="update" />
<MESSAGE value="feat: add landing page device images and fix machine branding" />
<option name="LAST_COMMIT_MESSAGE" value="feat: add landing page device images and fix machine branding" />
</component> </component>
</project> </project>
+9 -21
View File
@@ -1,49 +1,37 @@
import Header from '@/components/Header'; import LocationsSection from '@/components/LocationsSection';
import HeroSection from '@/components/HeroSection'; import ShowcaseSection from "@/components/ShowcaseSection";
import TrustedBySection from '@/components/TrustedBySection';
import FeaturesSection from '@/components/FeaturesSection'; import FeaturesSection from '@/components/FeaturesSection';
import AboutSection from '@/components/AboutSection'; import AboutSection from '@/components/AboutSection';
import HeroSection from '@/components/HeroSection';
import CartDrawer from '@/components/CartDrawer';
import Footer from '@/components/Footer';
import Header from '@/components/Header';
import TrustedBySection from '@/components/TrustedBySection';
import CatalogSection from '@/components/CatalogSection'; import CatalogSection from '@/components/CatalogSection';
import LocationsSection from '@/components/LocationsSection';
import IntroVideoSection from '@/components/IntroVideoSection'; import IntroVideoSection from '@/components/IntroVideoSection';
import MapSection from '@/components/MapSection'; import MapSection from '@/components/MapSection';
import TicketForm from '@/components/TicketForm'; import TicketForm from '@/components/TicketForm';
import Footer from '@/components/Footer';
import CartDrawer from '@/components/CartDrawer';
import ChatWidget from '@/components/ChatWidget'; import ChatWidget from '@/components/ChatWidget';
import ShowcaseSection from "@/components/ShowcaseSection";
export default function HomePage() { export default function HomePage() {
return ( return (
<main className="relative bg-page"> <main className="relative bg-page">
<Header/> <Header/>
<CartDrawer/> <CartDrawer/>
{/*faz 1*/}
{/*<ChatWidget/>*/} {/*<ChatWidget/>*/}
<HeroSection/> <HeroSection/>
<ShowcaseSection/> <ShowcaseSection/>
{/*<TrustedBySection/>*/} {/*<TrustedBySection/>*/}
<FeaturesSection/> <FeaturesSection/>
<AboutSection/> <AboutSection/>
{/*<CatalogSection/>*/} {/*<CatalogSection/>*/}
<LocationsSection/> <LocationsSection/>
{/*<IntroVideoSection/>*/} {/*<IntroVideoSection/>*/}
{/*<MapSection/>*/} {/*<MapSection/>*/}
{/*<TicketForm/>*/} {/*<TicketForm/>*/}
<Footer/> <Footer/>
</main> </main>
); );
+5 -5
View File
@@ -11,8 +11,7 @@ import {
selectIsDrawerOpen, selectIsDrawerOpen,
closeDrawer, closeDrawer,
removeFromCart, removeFromCart,
incrementQty, setQuantity,
decrementQty,
} from '@/store/cartSlice'; } from '@/store/cartSlice';
import {useLanguage} from '@/app/context/LanguageContext'; import {useLanguage} from '@/app/context/LanguageContext';
import api from "@/lib/axios"; import api from "@/lib/axios";
@@ -32,7 +31,7 @@ export default function CartDrawer() {
const handleCheckout = async () => { const handleCheckout = async () => {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// TODO: Connect to payment gateway API. // TODO: Connect to payment gateway API..
// try { // try {
// const { data } = await axios.post('/api/payment/create', { // const { data } = await axios.post('/api/payment/create', {
@@ -48,6 +47,7 @@ export default function CartDrawer() {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
await message.info(t.cart.checkoutToast); await message.info(t.cart.checkoutToast);
}; };
return ( return (
@@ -76,10 +76,10 @@ export default function CartDrawer() {
<InputNumber <InputNumber
size="small" size="small"
min={1} min={1}
precision={0}
value={item.qty} value={item.qty}
onChange={(val) => { onChange={(val) => {
if (val > item.qty) dispatch(incrementQty(item.id)); if (val !== null) dispatch(setQuantity({id: item.id, qty: val}));
else if (val < item.qty) dispatch(decrementQty(item.id));
}} }}
className="w-16" className="w-16"
/> />
+16 -5
View File
@@ -36,6 +36,11 @@ export default function Header() {
return () => window.removeEventListener('scroll', onScroll); return () => window.removeEventListener('scroll', onScroll);
}, []); }, []);
console.log(
"%c👋 Hamed Abdollahzade · Frontend Developer",
"font-size:14px;font-weight:600;"
);
return ( return (
<header <header
className={`fixed top-0 inset-x-0 z-50 transition-all duration-300 ${ className={`fixed top-0 inset-x-0 z-50 transition-all duration-300 ${
@@ -75,16 +80,15 @@ export default function Header() {
{t.nav.login} {t.nav.login}
</Button> </Button>
{/* faz 1 */} <Badge count={cartCount} size="small" offset={[-2, 2]}>
{/* <Badge count={cartCount} size="small" offset={[-2, 2]}>
<Button <Button
shape="circle" shape="circle"
size="large" size="large"
icon={<ShoppingCartOutlined/>} icon={<ShoppingCartOutlined/>}
onClick={() => dispatch(openDrawer())} onClick={() => dispatch(openDrawer())}
aria-label="cart" aria-label={t.cart.title}
/> />
</Badge>*/} </Badge>
<button <button
className="xl:hidden text-brand-400 text-2xl" className="xl:hidden text-brand-400 text-2xl"
@@ -112,7 +116,14 @@ export default function Header() {
<div className="flex items-center gap-3 pt-2 border-t border-subtle"> <div className="flex items-center gap-3 pt-2 border-t border-subtle">
<LanguageToggle/> <LanguageToggle/>
<ThemeToggle/> <ThemeToggle/>
<Button icon={<UserOutlined/>} className="flex-1"> <Button
icon={<UserOutlined/>}
className="flex-1"
href="https://panel.my-rm.com"
target="_blank"
rel="noopener noreferrer"
onClick={() => setMobileOpen(false)}
>
{t.nav.login} {t.nav.login}
</Button> </Button>
</div> </div>
+2 -2
View File
@@ -9,8 +9,8 @@ const machinesFa = [
id: 'rm-35', id: 'rm-35',
name: 'روبات مارکت ۳۵ کانال', name: 'روبات مارکت ۳۵ کانال',
shortLabel: '۳۵ کانال', shortLabel: '۳۵ کانال',
priceLabel: '4,200,000,000 ریال', priceLabel: '4,180,000,000 ریال',
priceNumeric: 4200000000, priceNumeric: 4180000000,
description: 'یخچالدار، ۳۵ کانال اختصاصی، سیستم خنک‌کننده قدرتمند، تحویل نرم، مدیریت آنلاین ۲۴ ساعته.', description: 'یخچالدار، ۳۵ کانال اختصاصی، سیستم خنک‌کننده قدرتمند، تحویل نرم، مدیریت آنلاین ۲۴ ساعته.',
highlights: ['یخچالدار', '۳۵ کانال اختصاصی', 'تحویل نرم', 'مدیریت آنلاین ۲۴ ساعته'], highlights: ['یخچالدار', '۳۵ کانال اختصاصی', 'تحویل نرم', 'مدیریت آنلاین ۲۴ ساعته'],
image: '/images/machine-35-base.webp', image: '/images/machine-35-base.webp',
Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

+7
View File
@@ -22,6 +22,12 @@ const cartSlice = createSlice({
removeFromCart: (state, action) => { removeFromCart: (state, action) => {
state.items = state.items.filter((item) => item.id !== action.payload); state.items = state.items.filter((item) => item.id !== action.payload);
}, },
setQuantity: (state, action) => {
const { id, qty } = action.payload;
if (!Number.isSafeInteger(qty) || qty < 1) return;
const item = state.items.find((item) => item.id === id);
if (item) item.qty = qty;
},
incrementQty: (state, action) => { incrementQty: (state, action) => {
const item = state.items.find((item) => item.id === action.payload); const item = state.items.find((item) => item.id === action.payload);
if (item) item.qty += 1; if (item) item.qty += 1;
@@ -52,6 +58,7 @@ const cartSlice = createSlice({
export const { export const {
addToCart, addToCart,
removeFromCart, removeFromCart,
setQuantity,
incrementQty, incrementQty,
decrementQty, decrementQty,
clearCart, clearCart,