Commit 8a237ca4 authored by Abdul Moiz Lakhani's avatar Abdul Moiz Lakhani

wsi poc microfronted

parents
File added
{
"cSpell.words": [
"amlakhani",
"vuex"
]
}
\ No newline at end of file
{
"extends": ["plugin:vue/base"],
"plugins": ["jest", "vue"],
"parser": "vue-eslint-parser"
}
.DS_Store
node_modules
/dist
/coverage
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# wsi-poc
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
module.exports = {
preset: "@vue/cli-plugin-unit-jest",
collectCoverage: true,
transformIgnorePatterns: ["node_modules/(?!axios)"],
};
\ No newline at end of file
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "wsi-poc",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^1.6.0",
"core-js": "^3.8.3",
"flush-promises": "^1.0.2",
"vue": "^2.7.14",
"vue-router": "^3.4.3",
"vue-server-renderer": "^2.7.14",
"vue-template-compiler": "^2.7.14",
"vuex": "^3.5.1",
"vuex-router-sync": "^5.0.0"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-unit-jest": "~5.0.0",
"@vue/cli-service": "^5.0.8",
"@vue/test-utils": "^1.1.3",
"@vue/vue2-jest": "^27.0.0-alpha.2",
"babel-eslint": "^10.1.0",
"babel-jest": "^27.0.6",
"eslint": "^7.32.0",
"eslint-plugin-jest": "^27.6.0",
"eslint-plugin-vue": "^8.0.3",
"jest": "^27.0.5",
"node-sass": "^9.0.0",
"sass-loader": "^13.3.2",
"tailwindcss": "^3.3.5",
"vue-template-compiler": "^2.6.14"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "@babel/eslint-parser"
},
"rules": {},
"overrides": [
{
"files": [
"**/__tests__/*.{j,t}s?(x)",
"**/tests/unit/**/*.spec.{j,t}s?(x)"
],
"env": {
"jest": true,
"jest/globals": true
}
}
]
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
module.exports = {
plugins: [require("tailwindcss")],
};
\ No newline at end of file
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
<template>
<div data-test="app">
<app-header
:logoIcon="icon"
:logoImage="logo"
:cartIcon="cart"
:cartItems="cartItems"
:cartSubtotal="cartSubtotal"
@onClickLogo="onClickLogo"
@openDrawer="openDrawer"
/>
<router-view></router-view>
<side-drawer
:isDrawerOpen="isDrawerOpen"
:cartItems="cartItems"
:cartSubtotal="cartSubtotal"
@closeDrawer="closeDrawer"
@increaseQuantity="increaseQuantity"
@decreaseQuantity="decreaseQuantity"
/>
</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
// Components
import AppHeader from "wsi-poc-components/Header";
import SideDrawer from "wsi-poc-components/SideDrawer";
export default {
name: "App",
components: {
AppHeader,
SideDrawer,
},
data: function () {
return {
icon: require("./assets/ws_logo_icon.png"),
logo: require("./assets/ws_horizontal.svg"),
cart: require("./assets/grocery-store.png"),
};
},
computed: {
...mapGetters("cart", ["cartItems", "cartSubtotal"]),
...mapGetters("drawer", ["isDrawerOpen"]),
},
methods: {
...mapActions("drawer", ["openDrawer", "closeDrawer"]),
...mapActions("cart", ["increaseQuantity", "decreaseQuantity"]),
onClickLogo() {
this.$router.push("/");
},
},
};
</script>
import { shallowMount } from "@vue/test-utils";
import App from "../App.vue";
import AppHeader from "../components/Header.vue";
import SideDrawer from "../components/SideDrawer.vue";
describe("App.vue", () => {
it("renders app correctly", () => {
const wrapper = shallowMount(App, {
components: { AppHeader, SideDrawer },
stubs: ["router-view"],
});
expect(wrapper.find('[data-test="app"]').exists()).toBe(true);
});
});
\ No newline at end of file
import * as productList from "./products.json";
export { productList };
[
{
"price": 59.95,
"pid": "apilco-porcelain-ramekin",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0051/img76c.jpg",
"title": "Apilco Porcelain Ramekins"
},
{
"price": 79.95,
"pid": "apilco-porcelain-oval-au-gratin-baker",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0052/img29c.jpg",
"title": "Apilco Porcelain Au Gratin Bakers"
},
{
"price": 119.95,
"pid": "pillivuyt-coupe-porcelain-soup-and-pasta-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0007/img1c.jpg",
"title": "Pillivuyt Coupe Porcelain Soup/Pasta Plates"
},
{
"price": 107.95,
"pid": "pillivuyt-coupe-porcelain-cereal-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0006/img36c.jpg",
"title": "Pillivuyt Coupe Porcelain Cereal Bowls"
},
{
"price": 119.95,
"pid": "pillivuyt-coupe-porcelain-dinner-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0002/img91c.jpg",
"title": "Pillivuyt Coupe Porcelain Dinner Plates"
},
{
"price": 119.95,
"pid": "pillivuyt-coupe-porcelain-dinnerware-collection",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0005/img32c.jpg",
"title": "Pillivuyt Coupe Porcelain Dinnerware Collection"
},
{
"price": 107.95,
"pid": "pillivuyt-beaded-salad-plates",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202329/0055/img49c.jpg",
"title": "Pillivuyt Beaded Coupe Salad Plates"
},
{
"price": 129.95,
"pid": "pillivuyt-shallow-coupe-porcelain-serving-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0016/img11c.jpg",
"title": "Pillivuyt Coupe Porcelain Shallow Serving Bowl"
},
{
"price": 59.95,
"pid": "apilco-porcelain-souffle-dish",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202340/0455/img92c.jpg",
"title": "Apilco Porcelain Souffl\u00e9 Dishes"
},
{
"price": 119.95,
"pid": "pillivuyt-beaded-dinner-plates",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0022/img25c.jpg",
"title": "Pillivuyt Beaded Coupe Dinner Plates"
},
{
"price": 119.95,
"pid": "apilco-tradition-porcelain-dinnerware-collection",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0003/img1c.jpg",
"title": "Apilco Tradition Porcelain Dinnerware Collection"
},
{
"price": 119.95,
"pid": "apilco-tradition-porcelain-dinner-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0003/img33c.jpg",
"title": "Apilco Tradition Porcelain Dinner Plates"
},
{
"price": 79.95,
"pid": "apilco-tuileries-porcelain-salad-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0009/img80c.jpg",
"title": "Apilco Tuileries Porcelain Salad Serving Bowls"
},
{
"price": 89.95,
"pid": "gravy-boat-and-warming-base",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0033/img59c.jpg",
"title": "Pillivuyt Porcelain Gravy Boat with Warming Base"
},
{
"price": 107.95,
"pid": "pillivuyt-coupe-porcelain-salad-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0005/img10c.jpg",
"title": "Pillivuyt Coupe Porcelain Salad Plates"
},
{
"price": 107.95,
"pid": "pillivuyt-beaded-cereal-bowls",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202331/0044/img8c.jpg",
"title": "Pillivuyt Beaded Coupe Cereal Bowls"
},
{
"price": 69.95,
"pid": "pillivuyt-covered-butter-dish",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0023/img3c.jpg",
"title": "Pillivuyt Porcelain Covered Butter Dish"
},
{
"price": 89.95,
"pid": "apilco-zen-porcelain-platter",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0022/img85c.jpg",
"title": "Apilco Zen Porcelain Platters"
},
{
"price": 107.95,
"pid": "apilco-tradition-porcelain-cereal-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0016/img20c.jpg",
"title": "Apilco Tradition Porcelain Cereal Bowls"
},
{
"price": 149.95,
"pid": "pillivuyt-oval-porcelain-serving-platter",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0051/img15c.jpg",
"title": "Pillivuyt Oval Porcelain Serving Platters"
},
{
"price": 99.95,
"pid": "apilco-porcelain-deep-oval-roaster",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0051/img4c.jpg",
"title": "Apilco Porcelain Deep Oval Roasters"
},
{
"price": 67.95,
"pid": "pillivuyt-coupe-porcelain-bread-and-butter-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0033/img42c.jpg",
"title": "Pillivuyt Coupe Porcelain Appetizer Plates"
},
{
"price": 107.95,
"pid": "pillivuyt-plisse-cereal-bowls",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0035/img3c.jpg",
"title": "Pillivuyt Plisse Porcelain Cereal Bowls"
},
{
"price": 107.95,
"pid": "apilco-tradition-blue-banded-porcelain-cereal-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0016/img26c.jpg",
"title": "Apilco Tradition Blue-Banded Porcelain Cereal Bowls"
},
{
"price": 149.95,
"pid": "pillivuyt-porcelain-rectangular-roaster",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0023/img46c.jpg",
"title": "Pillivuyt Porcelain Rectangular Roasters"
},
{
"price": 107.95,
"pid": "apilco-tradition-blue-banded-porcelain-salad-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0013/img88c.jpg",
"title": "Apilco Tradition Blue-Banded Porcelain Salad Plates"
},
{
"price": 107.95,
"pid": "apilco-tradition-porcelain-salad-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0003/img86c.jpg",
"title": "Apilco Tradition Porcelain Salad Plates"
},
{
"price": 107.95,
"pid": "pillivuyt-coupe-porcelain-mug",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0005/img32c.jpg",
"title": "Pillivuyt Coupe Porcelain Mugs"
},
{
"price": 119.95,
"pid": "pillivuyt-plisse-dinner-plates",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0002/img85c.jpg",
"title": "Pillivuyt Plisse Porcelain Dinner Plates"
},
{
"price": 119.95,
"pid": "apilco-tradition-blue-banded-porcelain-dinner-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0014/img87c.jpg",
"title": "Apilco Tradition Blue-Banded Porcelain Dinner Plates"
},
{
"price": 119.95,
"pid": "apilco-tuileries-porcelain-dinner-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0030/img77c.jpg",
"title": "Apilco Tuileries Porcelain Dinner Plates"
},
{
"price": 119.95,
"pid": "pillivuyt-perle-pasta-bowls",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0052/img18c.jpg",
"title": "Pillivuyt Perle Porcelain Pasta Bowls"
},
{
"price": 99.95,
"pid": "pillivuyt-coupe-porcelain-platter",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202326/0046/img95c.jpg",
"title": "Pillivuyt Coupe Porcelain Platter"
},
{
"price": 99.95,
"pid": "apilco-octagonal-porcelain-serving-platter",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0013/img8c.jpg",
"title": "Apilco Octagonal Porcelain Serving Platter"
},
{
"price": 139.95,
"pid": "pillivuyt-porcelain-cake-stand",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0021/img74c.jpg",
"title": "Pillivuyt Porcelain Cake Stands"
},
{
"price": 67.95,
"pid": "pillivuyt-beaded-bread-and-butter-plates",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202326/0060/img8c.jpg",
"title": "Pillivuyt Beaded Coupe Bread & Butter Plates"
},
{
"price": 119.95,
"pid": "pillivuyt-beaded-pasta-bowls",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202325/0024/img49c.jpg",
"title": "Pillivuyt Beaded Coupe Pasta Bowls, Set of 4"
},
{
"price": 119.95,
"pid": "pillivuyt-queen-anne-porcelain-cereal-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0011/img30c.jpg",
"title": "Pillivuyt Queen Anne Porcelain Cereal Bowls"
},
{
"price": 159.95,
"pid": "pillivuyt-beaded-oval-platter",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202336/0066/img58c.jpg",
"title": "Pillivuyt Beaded Coupe Oval Platter"
},
{
"price": 129.95,
"pid": "pillivuyt-beaded-serving-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202334/0077/img21c.jpg",
"title": "Pillivuyt Beaded Coupe Serving Bowl"
}
]
@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap");
@import "./tailwind.scss";
* {
font-family: Roboto, Arial, sans-serif;
}
.disable-scroll {
overflow: hidden;
}
\ No newline at end of file
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
\ No newline at end of file
<svg width="338" height="25" viewBox="0 0 338 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M34.7532 1.77755C34.4716 1.78806 34.1468 1.85114 33.7749 1.96678C33.4103 2.08243 33.0638 2.22961 32.7534 2.41535C32.3599 2.65364 32.0422 2.92699 31.8004 3.23888C31.5621 3.54727 31.3491 3.98181 31.1723 4.53551C30.3745 7.04466 29.4504 9.98134 28.3999 13.3351C27.3458 16.6888 26.2087 20.2668 24.9886 24.062H23.4436L17.4224 6.23514L11.163 24.0655H9.6757C8.56748 20.2597 7.41956 16.3068 6.23192 12.2136C5.04429 8.117 4.25013 5.37306 3.84221 3.98181C3.74114 3.64539 3.59314 3.34401 3.39821 3.08469C3.20327 2.82186 2.93615 2.58356 2.60043 2.36628C2.32248 2.18055 1.99398 2.04038 1.61856 1.94926C1.24314 1.85815 0.903812 1.79857 0.600586 1.77755V0.621094H10.3183V1.78105C9.46633 1.82661 8.74076 1.90721 8.14513 2.02636C7.5459 2.14901 7.24629 2.34876 7.24629 2.62911C7.24629 2.73775 7.26072 2.88143 7.29321 3.06016C7.32931 3.24238 7.35819 3.38606 7.37985 3.4947C7.63615 4.4514 8.09099 6.03539 8.74798 8.24316C9.40136 10.4509 10.376 13.7556 11.6611 18.1606L17.6137 0.950507H19.2562L25.2666 18.5251C26.0788 15.8232 26.7719 13.4612 27.3603 11.4392C27.9451 9.41713 28.4252 7.68947 28.8078 6.24916C29.0785 5.23639 29.2482 4.54252 29.3132 4.16755C29.3782 3.79257 29.4143 3.47367 29.4143 3.21435C29.4143 2.84639 29.1544 2.5345 28.6345 2.28568C28.1111 2.03337 27.2664 1.86516 26.104 1.77755V0.621094H34.7532V1.77755V1.77755Z" fill="#1A1A1A"/>
<path d="M47.0052 23.7711H36.2695V22.6147C36.5728 22.5937 37.0059 22.5621 37.5799 22.5166C38.1503 22.471 38.5546 22.4079 38.7892 22.3203C39.161 22.1802 39.4281 21.9874 39.5978 21.7421C39.7638 21.4968 39.8505 21.1569 39.8505 20.7223V3.95027C39.8505 3.56829 39.7891 3.24939 39.6664 2.99357C39.54 2.73775 39.2513 2.52398 38.7928 2.34876C38.4535 2.2191 38.0347 2.09645 37.5258 1.9808C37.0132 1.86515 36.598 1.79857 36.2731 1.77754V0.621094H47.0088V1.78105C46.6622 1.79156 46.2435 1.83362 45.767 1.9037C45.2869 1.97379 44.8645 2.06491 44.5072 2.17354C44.0776 2.30671 43.796 2.51697 43.648 2.80784C43.5036 3.10221 43.4314 3.42812 43.4314 3.78557V20.5401C43.4314 20.901 43.5145 21.2199 43.6769 21.4968C43.8393 21.7736 44.1137 21.9944 44.5072 22.1556C44.7418 22.2432 45.1281 22.3378 45.6551 22.4395C46.1857 22.5446 46.6406 22.6007 47.0088 22.6112V23.7711H47.0052Z" fill="#1A1A1A"/>
<path d="M69.0687 16.885L68.567 23.7711H49.9258V22.6147C50.1965 22.5937 50.5828 22.5551 51.0954 22.4991C51.6044 22.443 51.9617 22.3729 52.1603 22.2853C52.496 22.1451 52.7414 21.9383 52.8931 21.665C53.0483 21.3952 53.1205 21.0447 53.1205 20.6207V4.04489C53.1205 3.67693 53.0555 3.35102 52.9292 3.06716C52.7992 2.78331 52.5465 2.55552 52.1639 2.3803C51.9076 2.25064 51.5466 2.12098 51.0809 1.99482C50.6189 1.86866 50.2326 1.79507 49.9294 1.77404V0.621094H59.9972V1.78105C59.6832 1.79156 59.2789 1.84413 58.7771 1.94225C58.2789 2.04037 57.9216 2.12798 57.6941 2.20508C57.3151 2.33474 57.0552 2.55903 56.9144 2.87442C56.7736 3.18982 56.705 3.52624 56.705 3.88719V19.4362C56.705 20.1546 56.7411 20.7118 56.8133 21.1078C56.8855 21.5038 57.0588 21.8122 57.3295 22.0295C57.5858 22.2257 57.9685 22.3554 58.4811 22.4149C58.9901 22.4745 59.7012 22.5061 60.6217 22.5061C61.0368 22.5061 61.47 22.4955 61.9176 22.4745C62.3653 22.4535 62.7912 22.4079 63.1955 22.3449C63.589 22.2783 63.9464 22.1907 64.2785 22.075C64.6106 21.9629 64.856 21.8157 65.0113 21.644C65.4697 21.1429 66.0076 20.3859 66.614 19.3661C67.2277 18.3498 67.6501 17.5263 67.8847 16.8955H69.0687V16.885Z" fill="#1A1A1A"/>
<path d="M90.2878 16.885L89.786 23.7711H71.1484V22.6147C71.4192 22.5937 71.8054 22.5551 72.318 22.4991C72.8234 22.443 73.1808 22.3729 73.3829 22.2853C73.7186 22.1451 73.9677 21.9383 74.1157 21.665C74.2673 21.3952 74.3431 21.0447 74.3431 20.6207V4.04489C74.3431 3.67693 74.2782 3.35102 74.1482 3.06716C74.0219 2.78331 73.7656 2.55552 73.3829 2.3803C73.1266 2.25064 72.7656 2.12098 72.3 1.99482C71.8343 1.86866 71.4517 1.79507 71.1484 1.77404V0.621094H81.2163V1.78105C80.9022 1.79156 80.4979 1.84413 79.9961 1.94225C79.4944 2.04037 79.137 2.12798 78.9132 2.20508C78.5341 2.33474 78.2742 2.55903 78.1335 2.87442C77.9927 3.18982 77.9241 3.52624 77.9241 3.88719V19.4362C77.9241 20.1546 77.9602 20.7118 78.036 21.1078C78.1082 21.5038 78.2815 21.8122 78.545 22.0295C78.8049 22.2257 79.1875 22.3554 79.6965 22.4149C80.2055 22.4745 80.9202 22.5061 81.8408 22.5061C82.2559 22.5061 82.6891 22.4955 83.1367 22.4745C83.5843 22.4535 84.0103 22.4079 84.4146 22.3449C84.808 22.2783 85.169 22.1907 85.4975 22.075C85.8296 21.9629 86.0715 21.8157 86.2303 21.644C86.6888 21.1429 87.2266 20.3859 87.8331 19.3661C88.4467 18.3498 88.8691 17.5263 89.1037 16.8955H90.2878V16.885Z" fill="#1A1A1A"/>
<path d="M102.958 23.7711H92.2188V22.6147C92.522 22.5937 92.9551 22.5621 93.5291 22.5166C94.0995 22.471 94.5038 22.4079 94.7384 22.3203C95.1102 22.1802 95.3773 21.9874 95.5434 21.7421C95.7131 21.4968 95.7997 21.1569 95.7997 20.7223V3.95027C95.7997 3.56829 95.7383 3.24939 95.612 2.99357C95.4929 2.73775 95.2005 2.52398 94.742 2.34876C94.4027 2.2191 93.9803 2.09645 93.4714 1.9808C92.9624 1.86515 92.5472 1.79857 92.2224 1.77754V0.621094H102.962V1.78105C102.615 1.79156 102.196 1.83362 101.72 1.9037C101.236 1.97379 100.814 2.06491 100.456 2.17354C100.03 2.30671 99.7489 2.51697 99.6008 2.80784C99.4565 3.10221 99.3843 3.42812 99.3843 3.78557V20.5401C99.3843 20.901 99.4637 21.2199 99.6261 21.4968C99.7886 21.7736 100.067 21.9944 100.456 22.1556C100.695 22.2432 101.077 22.3378 101.608 22.4395C102.139 22.5446 102.59 22.6007 102.962 22.6112V23.7711H102.958Z" fill="#1A1A1A"/>
<path d="M130.077 23.7705H120.161V22.614C121.035 22.5615 121.76 22.4528 122.338 22.2881C122.912 22.1234 123.201 21.9237 123.201 21.6854C123.201 21.5872 123.19 21.4681 123.168 21.3244C123.143 21.1842 123.11 21.0581 123.063 20.9494L121.089 15.7594H112.718C112.407 16.5199 112.147 17.1822 111.952 17.7499C111.757 18.3176 111.584 18.8363 111.425 19.3164C111.281 19.786 111.18 20.1645 111.126 20.4553C111.068 20.7497 111.039 20.988 111.039 21.1737C111.039 21.6083 111.393 21.9482 112.1 22.1865C112.808 22.4283 113.598 22.5685 114.49 22.6105V23.767H105.509V22.6105C105.798 22.5895 106.162 22.5264 106.599 22.4213C107.036 22.3197 107.393 22.1795 107.675 22.0043C108.122 21.7099 108.469 21.405 108.714 21.0826C108.963 20.7637 109.202 20.3187 109.436 19.7544C110.635 16.8493 111.956 13.5902 113.4 9.96666C114.847 6.34311 116.136 3.11907 117.266 0.291016H118.609L126.558 20.2591C126.727 20.6831 126.919 21.0265 127.132 21.2859C127.345 21.5487 127.641 21.801 128.023 22.0533C128.28 22.2075 128.615 22.3337 129.03 22.4353C129.446 22.5404 129.792 22.5965 130.074 22.607V23.7705H130.077ZM120.482 14.3086L116.869 5.32333L113.306 14.3086H120.482Z" fill="#1A1A1A"/>
<path d="M161.705 23.7711H151.168V22.6147C151.55 22.6042 152.041 22.5656 152.64 22.4991C153.236 22.4325 153.651 22.3414 153.875 22.2222C154.225 22.0154 154.478 21.7806 154.64 21.5108C154.803 21.2445 154.882 20.9116 154.882 20.5086V3.67342H154.629L146.493 23.3962H145.655L137.909 3.26341H137.688V17.0813C137.688 18.4199 137.779 19.4362 137.948 20.1336C138.122 20.8275 138.389 21.3286 138.746 21.6335C138.992 21.8612 139.501 22.0785 140.277 22.2853C141.049 22.492 141.555 22.6007 141.789 22.6112V23.7676H132.158V22.6112C132.664 22.5656 133.194 22.485 133.747 22.3659C134.302 22.2467 134.728 22.068 135.032 21.8262C135.425 21.5213 135.692 21.0517 135.837 20.4209C135.985 19.7902 136.057 18.7353 136.057 17.2565V5.41861C136.057 4.73175 135.97 4.17455 135.801 3.7365C135.634 3.30196 135.393 2.94801 135.079 2.67467C134.732 2.38381 134.31 2.16303 133.801 2.02285C133.299 1.88268 132.801 1.80208 132.31 1.77754V0.621094H140.436L147.269 17.9994L153.099 3.46316C153.312 2.93049 153.492 2.37329 153.648 1.79156C153.796 1.20983 153.879 0.820844 153.889 0.624598H161.665V1.78455C161.351 1.79507 160.954 1.84413 160.467 1.93174C159.976 2.01935 159.618 2.09995 159.398 2.17705C159.019 2.31021 158.755 2.52398 158.625 2.82886C158.492 3.13375 158.423 3.46316 158.423 3.82411V20.5121C158.423 20.894 158.492 21.2129 158.625 21.4758C158.759 21.7351 159.019 21.9629 159.398 22.1591C159.6 22.2678 159.958 22.3694 160.474 22.4605C160.99 22.5516 161.398 22.6042 161.701 22.6182V23.7711H161.705Z" fill="#1A1A1A"/>
<path d="M179.478 13.1492C179.98 13.6924 180.355 14.2882 180.597 14.9365C180.836 15.5848 180.958 16.3382 180.958 17.1968C180.958 19.2434 180.179 20.929 178.623 22.2537C177.063 23.5818 175.132 24.2442 172.822 24.2442C171.757 24.2442 170.696 24.083 169.627 23.7641C168.562 23.4452 167.642 23.0562 166.873 22.5971L166.151 23.7886H164.808L164.573 15.8616H165.934C166.216 16.8394 166.544 17.7225 166.92 18.511C167.291 19.2995 167.79 20.0354 168.403 20.7222C168.988 21.3636 169.67 21.8752 170.446 22.2572C171.226 22.6356 172.129 22.8284 173.161 22.8284C173.934 22.8284 174.609 22.7303 175.186 22.5375C175.764 22.3413 176.229 22.0609 176.59 21.7035C176.948 21.3425 177.211 20.922 177.388 20.4384C177.565 19.9548 177.648 19.3941 177.648 18.7633C177.648 17.8381 177.381 16.9725 176.843 16.1735C176.305 15.3745 175.5 14.7648 174.439 14.3513C173.71 14.0709 172.876 13.759 171.934 13.4191C170.995 13.0792 170.179 12.7532 169.497 12.4519C168.154 11.8666 167.111 11.0957 166.364 10.146C165.62 9.19628 165.245 7.95222 165.245 6.4208C165.245 5.54119 165.432 4.71766 165.801 3.96071C166.169 3.19675 166.692 2.5169 167.378 1.92115C168.028 1.35694 168.793 0.911882 169.681 0.592982C170.566 0.270577 171.486 0.109375 172.454 0.109375C173.551 0.109375 174.533 0.274082 175.403 0.596486C176.269 0.922395 177.063 1.30437 177.778 1.73892L178.467 0.628026H179.81L179.944 8.31317H178.587C178.338 7.43357 178.06 6.58901 177.753 5.783C177.442 4.98049 177.045 4.24807 176.551 3.59625C176.071 2.96546 175.482 2.46083 174.785 2.08936C174.089 1.71439 173.24 1.52515 172.233 1.52515C171.165 1.52515 170.262 1.85807 169.511 2.5204C168.761 3.18273 168.385 3.99575 168.385 4.95245C168.385 5.95471 168.627 6.78525 169.107 7.44058C169.587 8.0994 170.288 8.63908 171.205 9.06311C172.024 9.44509 172.829 9.771 173.619 10.0514C174.41 10.3282 175.172 10.6261 175.912 10.9415C176.583 11.2218 177.233 11.5442 177.854 11.9052C178.478 12.2521 179.02 12.6726 179.478 13.1492Z" fill="#1A1A1A"/>
<path d="M206.631 13.0824C207.136 13.6256 207.504 14.2248 207.746 14.8696C207.991 15.5179 208.107 16.2714 208.107 17.13C208.107 19.1765 207.331 20.8586 205.771 22.1868C204.216 23.515 202.281 24.1773 199.974 24.1773C198.913 24.1773 197.844 24.0161 196.779 23.6972C195.718 23.3748 194.801 22.9858 194.025 22.5302L193.303 23.7182H191.96L191.726 15.7913H193.09C193.368 16.769 193.697 17.6521 194.072 18.4406C194.444 19.2291 194.942 19.965 195.559 20.6519C196.144 21.2932 196.823 21.8048 197.602 22.1868C198.378 22.5688 199.285 22.758 200.313 22.758C201.086 22.758 201.761 22.6599 202.338 22.4637C202.916 22.2674 203.389 21.9906 203.743 21.6296C204.1 21.2722 204.367 20.8481 204.544 20.361C204.714 19.8774 204.804 19.3202 204.804 18.6859C204.804 17.7607 204.533 16.8952 203.995 16.0962C203.458 15.2972 202.656 14.6909 201.591 14.2739C200.862 13.9935 200.032 13.6816 199.086 13.3382C198.144 12.9983 197.335 12.6759 196.653 12.371C195.307 11.7822 194.263 11.0148 193.52 10.0616C192.772 9.11189 192.401 7.86783 192.401 6.33641C192.401 5.45681 192.585 4.63327 192.957 3.87282C193.328 3.11236 193.852 2.43251 194.538 1.83326C195.187 1.26905 195.956 0.823991 196.841 0.505091C197.729 0.186191 198.653 0.0214844 199.617 0.0214844C200.714 0.0214844 201.696 0.186191 202.566 0.5121C203.436 0.838009 204.226 1.21999 204.945 1.65453L205.634 0.54364H206.977L207.111 8.22878H205.746C205.501 7.34918 205.223 6.50462 204.916 5.69861C204.609 4.8961 204.208 4.16368 203.714 3.51186C203.234 2.88107 202.645 2.37644 201.949 2.00497C201.256 1.63 200.404 1.44077 199.393 1.44077C198.328 1.44077 197.422 1.77368 196.671 2.43601C195.92 3.09835 195.545 3.90786 195.545 4.86456C195.545 5.86682 195.79 6.69736 196.267 7.35619C196.75 8.01151 197.451 8.55469 198.368 8.97873C199.183 9.36071 199.988 9.68661 200.779 9.96697C201.57 10.2438 202.335 10.5417 203.071 10.8571C203.743 11.1409 204.389 11.4633 205.013 11.8208C205.627 12.1888 206.169 12.6058 206.631 13.0824Z" fill="#1A1A1A"/>
<path d="M229.982 3.29413C231.033 4.35947 231.859 5.64559 232.451 7.15248C233.043 8.65937 233.343 10.324 233.343 12.1533C233.343 13.9896 233.04 15.6612 232.433 17.161C231.831 18.6609 230.989 19.94 229.914 20.9948C228.874 22.0392 227.661 22.8452 226.282 23.4094C224.903 23.9736 223.438 24.2574 221.878 24.2574C220.221 24.2574 218.687 23.9561 217.283 23.3533C215.879 22.7506 214.673 21.9095 213.659 20.8336C212.651 19.7788 211.861 18.4962 211.28 16.9928C210.702 15.4859 210.417 13.8739 210.417 12.1568C210.417 10.2749 210.72 8.59629 211.323 7.12094C211.933 5.64909 212.763 4.37349 213.828 3.29413C214.879 2.2288 216.106 1.41227 217.499 0.848064C218.893 0.280352 220.355 0 221.875 0C223.456 0 224.947 0.287361 226.344 0.865587C227.751 1.44031 228.961 2.24982 229.982 3.29413ZM227.473 19.7087C228.102 18.7205 228.56 17.5991 228.842 16.348C229.13 15.0969 229.271 13.6987 229.271 12.1568C229.271 10.5658 229.109 9.10793 228.791 7.78327C228.473 6.4551 228.004 5.32318 227.39 4.39101C226.773 3.46585 226.001 2.74394 225.069 2.2288C224.142 1.71365 223.077 1.45433 221.875 1.45433C220.532 1.45433 219.391 1.7522 218.445 2.35145C217.503 2.9507 216.738 3.74971 216.142 4.75196C215.586 5.70867 215.164 6.83007 214.893 8.11268C214.615 9.39529 214.478 10.7445 214.478 12.1603C214.478 13.7267 214.626 15.139 214.915 16.4006C215.207 17.6622 215.666 18.7836 216.294 19.7613C216.9 20.718 217.658 21.4679 218.579 22.0041C219.499 22.5438 220.597 22.8101 221.871 22.8101C223.073 22.8101 224.152 22.5368 225.116 21.9936C226.084 21.4469 226.871 20.6865 227.473 19.7087Z" fill="#1A1A1A"/>
<path d="M258.909 1.71464C258.598 1.72516 258.118 1.81277 257.465 1.97397C256.815 2.13868 256.349 2.30689 256.071 2.48211C255.667 2.75545 255.396 3.27761 255.259 4.04857C255.118 4.81954 255.046 5.80077 255.046 6.98526V23.936H253.584L239.134 4.99476V16.9378C239.134 18.2764 239.217 19.3032 239.394 20.0216C239.571 20.74 239.834 21.2517 240.195 21.5566C240.452 21.7984 240.986 22.0191 241.791 22.2259C242.6 22.4326 243.127 22.5413 243.39 22.5518V23.7083H233.607V22.5518C233.911 22.5308 234.416 22.4221 235.138 22.2329C235.856 22.0437 236.3 21.8684 236.481 21.7178C236.874 21.4129 237.138 20.9468 237.286 20.323C237.434 19.6957 237.506 18.6269 237.506 17.1165V5.70966C237.506 5.21203 237.416 4.7109 237.239 4.20978C237.058 3.71215 236.817 3.32316 236.517 3.05332C236.113 2.69237 235.564 2.38749 234.874 2.13167C234.185 1.87585 233.629 1.73567 233.203 1.71464V0.558192H240.018L253.425 18.2063V7.19202C253.425 5.84282 253.335 4.80903 253.155 4.08362C252.974 3.36171 252.718 2.8781 252.379 2.6398C252.068 2.43305 251.552 2.23329 250.841 2.03705C250.13 1.8408 249.588 1.73217 249.216 1.71114V0.554688H258.912V1.71464H258.909Z" fill="#1A1A1A"/>
<path d="M278.243 3.29413C279.297 4.35947 280.12 5.64559 280.716 7.15248C281.308 8.65937 281.604 10.324 281.604 12.1533C281.604 13.9896 281.304 15.6612 280.698 17.161C280.092 18.6609 279.254 19.94 278.178 20.9948C277.135 22.0392 275.926 22.8452 274.547 23.4094C273.168 23.9736 271.702 24.2574 270.143 24.2574C268.486 24.2574 266.952 23.9561 265.548 23.3533C264.14 22.7506 262.934 21.9095 261.927 20.8336C260.92 19.7788 260.126 18.4962 259.548 16.9928C258.97 15.4859 258.682 13.8739 258.682 12.1568C258.682 10.2749 258.985 8.59629 259.591 7.12094C260.194 5.64909 261.028 4.37349 262.097 3.29413C263.151 2.2288 264.371 1.41227 265.768 0.848064C267.165 0.280352 268.62 0 270.143 0C271.724 0 273.215 0.287361 274.615 0.865587C276.012 1.44031 277.225 2.24982 278.243 3.29413ZM275.742 19.7087C276.37 18.7205 276.825 17.5991 277.11 16.348C277.395 15.0969 277.539 13.6987 277.539 12.1568C277.539 10.5658 277.381 9.10793 277.063 7.78327C276.738 6.4551 276.272 5.32318 275.655 4.39101C275.038 3.46585 274.269 2.74394 273.338 2.2288C272.406 1.71365 271.341 1.45433 270.143 1.45433C268.8 1.45433 267.656 1.7522 266.714 2.35145C265.775 2.9507 265.002 3.74971 264.41 4.75196C263.851 5.70867 263.436 6.83007 263.158 8.11268C262.887 9.39529 262.746 10.7445 262.746 12.1603C262.746 13.7267 262.887 15.139 263.179 16.4006C263.476 17.6622 263.934 18.7836 264.558 19.7613C265.161 20.718 265.927 21.4679 266.843 22.0041C267.764 22.5438 268.861 22.8101 270.139 22.8101C271.338 22.8101 272.421 22.5368 273.381 21.9936C274.352 21.4469 275.135 20.6865 275.742 19.7087Z" fill="#1A1A1A"/>
<path d="M311.304 23.7047H300.767V22.5483C301.146 22.5343 301.637 22.4992 302.236 22.4327C302.836 22.3661 303.247 22.275 303.475 22.1558C303.821 21.949 304.074 21.7142 304.236 21.4479C304.399 21.1781 304.482 20.8452 304.482 20.4422V3.60351H304.229L296.096 23.3298H295.255L287.508 3.197H287.292V17.0148C287.292 18.3535 287.378 19.3698 287.552 20.0672C287.721 20.7611 287.988 21.2657 288.349 21.5671C288.595 21.7948 289.104 22.0121 289.876 22.2189C290.649 22.4256 291.154 22.5343 291.389 22.5448V23.7012H281.758V22.5448C282.26 22.4992 282.79 22.4186 283.346 22.2995C283.902 22.1803 284.328 22.0016 284.628 21.7633C285.021 21.4584 285.288 20.9923 285.436 20.3615C285.581 19.7308 285.653 18.6759 285.653 17.1971V5.35221C285.653 4.66885 285.573 4.10815 285.404 3.6701C285.238 3.23555 284.992 2.88161 284.682 2.60827C284.335 2.3139 283.909 2.09662 283.408 1.95645C282.902 1.81627 282.4 1.73217 281.909 1.71114V0.554688H290.042L296.872 17.933L302.706 3.39675C302.915 2.86409 303.099 2.30689 303.251 1.72165C303.402 1.13992 303.482 0.750934 303.496 0.554688H311.272V1.71114C310.958 1.72165 310.557 1.77071 310.07 1.85832C309.582 1.94593 309.229 2.02654 309.005 2.10363C308.622 2.23329 308.366 2.45057 308.232 2.75545C308.099 3.06033 308.03 3.39325 308.03 3.7507V20.4422C308.03 20.8241 308.099 21.143 308.232 21.4059C308.366 21.6652 308.626 21.8965 309.005 22.0927C309.203 22.2014 309.561 22.303 310.081 22.3941C310.597 22.4887 311.005 22.5378 311.308 22.5518V23.7047H311.304Z" fill="#1A1A1A"/>
<path d="M337.4 23.7045H327.487V22.548C328.364 22.492 329.086 22.3833 329.664 22.2221C330.241 22.0574 330.53 21.8577 330.53 21.6194C330.53 21.5212 330.519 21.4021 330.498 21.2584C330.476 21.1182 330.443 20.9921 330.396 20.8834L328.422 15.6969H320.054C319.737 16.4574 319.484 17.1232 319.289 17.6874C319.094 18.2551 318.914 18.7773 318.758 19.2539C318.61 19.7235 318.509 20.102 318.455 20.3963C318.401 20.6872 318.372 20.929 318.372 21.1147C318.372 21.5493 318.722 21.8857 319.426 22.124C320.134 22.3623 320.932 22.506 321.812 22.548V23.7045H312.831V22.548C313.12 22.527 313.484 22.4639 313.925 22.3588C314.362 22.2572 314.723 22.117 315.001 21.9418C315.448 21.6474 315.798 21.3425 316.04 21.0201C316.289 20.6977 316.531 20.2562 316.762 19.6919C317.961 16.7868 319.282 13.5242 320.729 9.90416C322.173 6.28061 323.462 3.05657 324.592 0.228516H325.935L333.887 20.1966C334.053 20.6206 334.245 20.964 334.458 21.2234C334.671 21.4827 334.967 21.742 335.349 21.9908C335.609 22.145 335.945 22.2712 336.36 22.3728C336.771 22.4779 337.118 22.534 337.4 22.5445V23.7045V23.7045ZM327.808 14.2426L324.195 5.26083L320.632 14.2426H327.808Z" fill="#1A1A1A"/>
</svg>
import Vue from "vue";
import App from "./App.vue";
import store from "./store";
import router from "./router";
// Stylesheet
import "wsi-poc-components/styles";
import "./assets/scss/tailwind.scss";
Vue.config.productionTip = false;
new Vue({
render: (h) => h(App),
store,
router,
}).$mount("#app");
import('./bootstrap');
\ No newline at end of file
import Vue from "vue";
import VueRouter from "vue-router";
import ProductList from "../views/ProductList.vue";
import ProductDetail from "../views/ProductDetail.vue";
Vue.use(VueRouter);
const routes = [
{ path: "/", component: ProductList },
{ path: "/product-detail/:productId", component: ProductDetail },
// Add more routes as needed
];
const router = new VueRouter({
routes,
mode: "history",
});
export default router;
\ No newline at end of file
// store.js
import Vue from "vue";
import Vuex from "vuex";
// Store Modules
import cart from "./modules/cart";
import product from "./modules/product";
import drawer from "./modules/drawer";
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
cart,
product,
drawer,
},
});
export default store;
\ No newline at end of file
import Vuex from "vuex";
import { createLocalVue } from "@vue/test-utils";
import cartModule from "../cart";
const localVue = createLocalVue();
localVue.use(Vuex);
const createItem = (pid, title, price) => ({ pid, title, price, quantity: 0 });
describe("Cart Module", () => {
let store;
beforeEach(() => {
store = new Vuex.Store({
modules: {
cart: cartModule,
},
});
});
it("correctly adds an item to the cart", () => {
const item = createItem("product-a", "Product A", 10);
store.dispatch("cart/addItemToCart", item);
expect(store.getters["cart/cartItems"]).toHaveLength(1);
});
it("correctly removes an item from the cart", () => {
const item = createItem("product-a", "Product A", 10);
store.dispatch("cart/addItemToCart", item);
store.dispatch("cart/removeItemFromCart", item);
expect(store.getters["cart/cartItems"]).toHaveLength(0);
});
it("correctly increments the quantity of an item in the cart", () => {
const item = createItem("product-a", "Product A", 10);
store.dispatch("cart/addItemToCart", item);
store.dispatch("cart/increaseQuantity", item.pid);
const cartItems = store.getters["cart/cartItems"];
expect(cartItems.length).toBe(1);
expect(cartItems[0].quantity).toBe(2);
});
it("correctly decrements the quantity of an item in the cart", () => {
const item = createItem("product-a", "Product A", 10);
store.dispatch("cart/addItemToCart", item);
store.dispatch("cart/increaseQuantity", item.pid);
store.dispatch("cart/decreaseQuantity", item.pid);
const cartItems = store.getters["cart/cartItems"];
expect(cartItems.length).toBe(2); // - 1
expect(cartItems[0].quantity).toBe(2); // - 1
});
it("correctly removes an item quantity is 1 in the cart if decrease it's quantity", () => {
const item = createItem("product-a", "Product A", 10);
store.dispatch("cart/decreaseQuantity", item.pid);
const cartItems = store.getters["cart/cartItems"];
expect(cartItems.length).toBe(2); // - 0
});
it("correctly removes an item when decreasing its quantity to 0", () => {
const item = createItem("product-a", "Product A", 10);
store.dispatch("cart/addItemToCart", item);
store.dispatch("cart/decreaseQuantity", item.pid);
expect(store.getters["cart/cartItems"]).toHaveLength(0);
});
it("calculates the cart subtotal correctly", () => {
const item1 = createItem("product-a", "Product A", 10);
const item2 = createItem("product-b", "Product B", 20);
store.dispatch("cart/addItemToCart", item1);
store.dispatch("cart/addItemToCart", item2);
store.dispatch("cart/increaseQuantity", item2.pid);
const subtotal = store.getters["cart/cartSubtotal"];
expect(subtotal).toBe(10 + (20 * 2));
});
});
\ No newline at end of file
import Vuex from "vuex";
import { createLocalVue } from "@vue/test-utils";
import drawerModule from "../drawer";
const localVue = createLocalVue();
localVue.use(Vuex);
describe("Drawer Module", () => {
let store;
beforeEach(() => {
store = new Vuex.Store({
modules: {
drawer: drawerModule,
},
});
});
it("correctly opens the drawer", () => {
store.dispatch("drawer/openDrawer");
expect(store.getters["drawer/isDrawerOpen"]).toBe(true);
expect(document.body.classList.contains("disable-scroll")).toBe(true);
});
it("correctly closes the drawer", () => {
store.dispatch("drawer/openDrawer");
store.dispatch("drawer/closeDrawer");
expect(store.getters["drawer/isDrawerOpen"]).toBe(false);
expect(document.body.classList.contains("disable-scroll")).toBe(false);
});
it("correctly sets drawer state with mutations", () => {
store.commit("drawer/setDrawerState", true);
expect(store.getters["drawer/isDrawerOpen"]).toBe(true);
});
});
import Vuex from "vuex";
import { createLocalVue } from "@vue/test-utils";
import axios from "axios";
import flushPromises from "flush-promises";
import { productList } from "../../../assets/dummy-data";
import productsModule from "../product";
const localVue = createLocalVue();
localVue.use(Vuex);
jest.mock("axios");
describe("Product Module", () => {
const mockedResponse = {
data: [productList[0], productList[2]].map((p) => ({
...p,
id: p.pid,
image: p.thumb_image,
description: "lorem ipsum",
})),
};
let store;
let commit;
beforeEach(() => {
commit = jest.fn();
store = new Vuex.Store({
modules: {
product: {
namespaced: true,
state: {
products: mockedResponse.data,
},
actions: productsModule.actions,
mutations: productsModule.mutations,
getters: productsModule.getters,
},
},
});
});
afterEach(() => {
jest.clearAllMocks();
});
it("should correctly retrieves products", async () => {
axios.get.mockResolvedValue(mockedResponse);
const expectedProductList = [
{
pid: "apilco_porcelain_ramekins_apilco-porcelain-ramekin",
title: "Apilco Porcelain Ramekins",
description: "lorem ipsum",
price: 59.95,
thumb_image:
"https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0051/img76c.jpg",
},
{
pid: "pillivuyt_coupe_porcelain_soup/pasta_plates_pillivuyt-coupe-porcelain-soup-and-pasta-plate",
title: "Pillivuyt Coupe Porcelain Soup/Pasta Plates",
description: "lorem ipsum",
price: 119.95,
thumb_image:
"https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0007/img1c.jpg",
},
];
await store.dispatch("product/fetchProducts", { commit });
await flushPromises();
expect(axios.get).toHaveBeenCalledWith("https://fakestoreapi.com/products");
const products = store.getters["product/products"];
expect(products).toEqual(expectedProductList);
});
it("should fetchProducts action handles error", async () => {
console.log = jest.fn();
axios.get.mockRejectedValue(new Error("Request failed"));
await store.dispatch("product/fetchProducts", { commit });
await flushPromises();
expect(console.log).toHaveBeenCalledWith("Error: ", "Request failed");
});
it("should correctly retrieves a product by ID", async () => {
const productId = "pillivuyt-coupe-porcelain-soup-and-pasta-plate";
const product = store.getters["product/getProductById"](productId);
expect(product).toEqual(
expect.objectContaining({
pid: productId,
})
);
});
});
const state = {
items: [],
};
const mutations = {
addItem(state, item) {
state.items.push({ ...item, quantity: 1 });
},
removeItem(state, item) {
state.items = [...state.items].filter((i) => i.pid !== item.pid);
},
incrementQuantity(state, itemId) {
const item = state.items.find((i) => i.pid === itemId);
if (item) {
item.quantity++;
}
},
decrementQuantity(state, itemId) {
const item = state.items.find((i) => i.pid === itemId);
if (item && item.quantity > 1) {
item.quantity--;
} else {
state.items = [...state.items].filter((i) => i.pid !== itemId);
}
},
};
const actions = {
addItemToCart({ commit }, item) {
commit("addItem", item);
},
removeItemFromCart({ commit }, item) {
commit("removeItem", item);
},
increaseQuantity({ commit }, itemId) {
commit("incrementQuantity", itemId);
},
decreaseQuantity({ commit }, itemId) {
commit("decrementQuantity", itemId);
},
};
const getters = {
cartItems: (state) => state.items,
cartSubtotal: (state) => {
return state.items.reduce(
(total, item) => total + item.price * item.quantity,
0
);
},
};
export default {
namespaced: true,
state,
mutations,
actions,
getters,
};
const state = {
drawerIsOpen: false,
};
const mutations = {
setDrawerState(state, isOpen) {
state.drawerIsOpen = isOpen;
},
};
const actions = {
openDrawer({ commit }) {
commit("setDrawerState", true);
document.body.classList.add('disable-scroll');
},
closeDrawer({ commit }) {
commit("setDrawerState", false);
document.body.classList.remove('disable-scroll');
},
};
const getters = {
isDrawerOpen: (state) => state.drawerIsOpen,
};
export default {
namespaced: true,
state,
mutations,
actions,
getters,
};
import axios from "axios";
const state = {
products: [],
loading: true,
};
const mutations = {
setProducts(state, products) {
state.products = products;
},
setLoading(state, status) {
state.loading = status;
},
};
const actions = {
async fetchProducts({ commit }) {
try {
const response = await axios.get("https://fakestoreapi.com/products");
const products = response.data.map((product) => ({
pid: `${product.title.toLowerCase().replace(/ /g, "_")}_${product.id}`,
title: product.title,
description: product.description,
price: product.price,
thumb_image: product.image,
}));
commit("setProducts", products);
commit("setLoading", false);
} catch (error) {
console.log("Error: ", error.message);
}
},
};
const getters = {
products: (state) => state.products,
getProductById: (state) => (pid) => {
const productArray = Object.values(state.products).filter(item => typeof item === 'object');
return productArray.find(product => product.pid === pid);
},
};
export default {
namespaced: true,
state,
mutations,
actions,
getters,
};
<template>
<div data-test="product-detail" class="max-w-2xl mx-auto p-4">
<div class="flex flex-col md:flex-row">
<div class="md:w-1/2">
<img
:src="product.thumb_image"
:alt="product.title"
class="w-full rounded-lg"
/>
</div>
<div class="md:w-1/2 mt-4 md:mt-0 md:ml-4">
<h1 class="text-2xl font-semibold">{{ product.title }}</h1>
<p class="text-gray-600 text-lg mt-2">{{ product.description }}</p>
<p class="text-2xl font-semibold text-primary mt-4">
{{ formatCurrency(product.price) }}
</p>
<div class="mt-4">
<div class="flex items-center">
<button
data-test="pd-dec-qty-btn"
@click="decreaseQuantity(product.pid)"
class="px-4 py-2 rounded bg-zinc-950 text-white"
>
-
</button>
<span class="px-4 py-2">{{ productCartQty }}</span>
<button
data-test="pd-inc-qty-btn"
@click="
!!productCartQty
? increaseQuantity(product.pid)
: addItemToCart(product)
"
class="px-4 py-2 rounded bg-zinc-950 text-white"
>
+
</button>
</div>
<button
data-test="pd-atc-btn"
v-if="productCartQty === 0"
@click="addItemToCart(product)"
class="px-4 py-2 rounded bg-zinc-950 text-white mt-4"
>
Add to Cart
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
name: "product-detail",
methods: {
...mapActions("cart", [
"increaseQuantity",
"decreaseQuantity",
"addItemToCart",
]),
formatCurrency(amount) {
return `$${amount.toFixed(2)}`;
},
},
computed: {
...mapGetters("product", ["getProductById"]),
...mapGetters("cart", ["cartItems"]),
product() {
return this.getProductById(this.$route.params.productId);
},
productCartQty() {
const product = this.cartItems.find(
(item) => item.pid === this.$route.params.productId
);
return product ? product.quantity : 0;
},
},
};
</script>
<template>
<main data-test="product-list" class="p-8 mx-auto">
<div
v-if="!loading"
class="grid md:grid-cols-3 sm:grid-cols-2 grid-cols-1 justify-items-center gap-8"
>
<single-product
data-test="single-product"
v-for="product in products"
:product="product"
:key="product.pid"
imgClass="h-[350px]"
:cartItems="cartItems"
@addItemToCart="addItemToCart"
@removeItemFromCart="removeItemFromCart"
@onClickProductTile="onClickProductTile"
/>
</div>
<p v-if="loading">Loading products...</p>
</main>
</template>
<script>
import { mapState, mapGetters, mapActions } from "vuex";
import SingleProduct from "wsi-poc-components/Product";
export default {
name: "product-list",
components: {
SingleProduct,
},
methods: {
...mapActions("product", ["fetchProducts"]),
...mapActions("cart", ["addItemToCart", "removeItemFromCart"]),
onClickProductTile(product) {
this.$router.push(`/product-detail/${product.pid}`);
},
},
computed: {
...mapGetters("cart", ["cartItems"]),
...mapState("product", ["products", "loading"]),
},
mounted() {
this.fetchProducts();
},
};
</script>
import { shallowMount, createLocalVue } from "@vue/test-utils";
import Vuex from "vuex";
import { productList } from "../../assets/dummy-data";
import ProductDetail from "../ProductDetail.vue";
import ProductModule from "../../store/modules/product";
import CartModule from "../../store/modules/cart";
const localVue = createLocalVue();
localVue.use(Vuex);
const $route = {
params: {
productId: "apilco-porcelain-ramekin",
},
};
describe("ProductDetail.vue", () => {
const productArray = Object.values(productList).filter(
(item) => typeof item === "object"
);
let store;
let modules = {
cart: {
actions: undefined,
state: undefined,
},
product: {
actions: undefined,
state: undefined,
},
};
beforeEach(() => {
modules.cart.state = {
items: [{ ...productArray[0], quantity: 1 }],
};
modules.product.state = {
products: productList,
};
modules.cart.actions = {
increaseQuantity: jest.fn(),
decreaseQuantity: jest.fn(),
addItemToCart: jest.fn(),
};
store = new Vuex.Store({
modules: {
cart: {
state: modules.cart.state,
actions: modules.cart.actions,
getters: CartModule.getters,
namespaced: true,
},
product: {
state: modules.product.state,
actions: modules.product.actions,
getters: ProductModule.getters,
namespaced: true,
},
},
});
});
it("renders ProductDetail correctly", () => {
const wrapper = shallowMount(ProductDetail, {
store,
localVue,
mocks: {
$route,
},
});
expect(wrapper.find('[data-test="product-detail"]').exists()).toBe(true);
});
it('calls store action "increaseQuantity" when "+" button is clicked', () => {
const wrapper = shallowMount(ProductDetail, {
store,
localVue,
mocks: {
$route,
},
});
const button = wrapper.find('[data-test="pd-inc-qty-btn"]');
button.trigger("click");
expect(modules.cart.actions.increaseQuantity).toHaveBeenCalled();
});
it('calls store action "decreaseQuantity" when "-" button is clicked', () => {
const wrapper = shallowMount(ProductDetail, {
store,
localVue,
mocks: {
$route,
},
});
const button = wrapper.find('[data-test="pd-dec-qty-btn"]');
button.trigger("click");
expect(modules.cart.actions.decreaseQuantity).toHaveBeenCalled();
});
it('calls store action "addItemToCart" when "Add to Cart" button is clicked', () => {
const wrapper = shallowMount(ProductDetail, {
store,
localVue,
mocks: {
$route: {
params: {
productId: "apilco-porcelain-oval-au-gratin-baker",
},
},
},
});
const button = wrapper.find('[data-test="pd-atc-btn"]');
button.trigger("click");
expect(modules.cart.actions.addItemToCart).toHaveBeenCalled();
});
});
import { shallowMount, createLocalVue } from "@vue/test-utils";
import Vuex from "vuex";
import { productList } from "../../assets/dummy-data";
import ProductList from "../ProductList.vue";
import SingleProduct from "../../components/Product.vue";
import ProductModule from "../../store/modules/product";
const localVue = createLocalVue();
localVue.use(Vuex);
describe("ProductList.vue", () => {
let store;
let modules = {
product: {
actions: undefined,
state: undefined,
},
};
beforeEach(() => {
modules.product.state = {
products: productList,
};
modules.product.actions = {
fetchProducts: jest.fn(), // Mock the action
};
store = new Vuex.Store({
modules: {
product: {
state: modules.product.state,
actions: modules.product.actions,
getters: ProductModule.getters,
namespaced: true,
},
},
});
});
it("renders ProductList correctly", () => {
const wrapper = shallowMount(ProductList, {
store,
localVue,
});
expect(wrapper.find('[data-test="product-list"]').exists()).toBe(true);
});
it("renders ProductList with list of 41 Products", () => {
const wrapper = shallowMount(ProductList, {
store,
localVue,
components: { SingleProduct },
});
const SingleProducts = wrapper.findAll('[data-test="single-product"]');
expect(SingleProducts).toHaveLength(41);
});
});
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
const { defineConfig } = require("@vue/cli-service");
module.exports = defineConfig({
publicPath: "http://localhost:8080/",
transpileDependencies: true,
devServer: {
port: 8080,
},
chainWebpack: (config) => {
config.optimization.delete("splitChunks");
config
.plugin("module-federation-plugin")
.use(require("webpack").container.ModuleFederationPlugin, [
{
remotes: {
"wsi-poc-components":
"wsi_poc_components@http://localhost:8081/remoteEntry.js",
},
shared: {
vue: {
eager: true,
singleton: false,
},
},
},
]);
},
});
module.exports = {
module: {
rules: [
// ... other rules omitted
// this will apply to both plain `.scss` files
// AND `<style lang="scss">` blocks in `.vue` files
{
test: /\.scss$/,
use: ["vue-style-loader", "css-loader", "sass-loader"],
},
],
},
// plugin omitted
};
{
"extends": ["plugin:vue/base"],
"plugins": ["jest", "vue"],
"parser": "vue-eslint-parser"
}
.DS_Store
node_modules
/dist
/coverage
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# wsi-poc
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
{
"name": "wsi_poc_components",
"exposes": {
"./Header": "./src/components/Header.vue",
"./Product": "./src/components/Product.vue",
"./SideDrawer": "./src/components/SideDrawer.vue",
"./styles": "./src/assets/scss/style.scss"
}
}
\ No newline at end of file
module.exports = {
preset: "@vue/cli-plugin-unit-jest",
collectCoverage: true,
transformIgnorePatterns: ["node_modules/(?!axios)"],
};
\ No newline at end of file
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "wsi-poc",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^1.6.0",
"core-js": "^3.8.3",
"flush-promises": "^1.0.2",
"vue": "^2.7.14",
"vue-router": "^3.4.3",
"vue-server-renderer": "^2.7.14",
"vue-template-compiler": "^2.7.14",
"vuex": "^3.5.1",
"vuex-router-sync": "^5.0.0"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-unit-jest": "~5.0.0",
"@vue/cli-service": "^5.0.8",
"@vue/test-utils": "^1.1.3",
"@vue/vue2-jest": "^27.0.0-alpha.2",
"babel-eslint": "^10.1.0",
"babel-jest": "^27.0.6",
"eslint": "^7.32.0",
"eslint-plugin-jest": "^27.6.0",
"eslint-plugin-vue": "^8.0.3",
"jest": "^27.0.5",
"node-sass": "^9.0.0",
"sass-loader": "^13.3.2",
"tailwindcss": "^3.3.5",
"vue-template-compiler": "^2.6.14"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "@babel/eslint-parser"
},
"rules": {},
"overrides": [
{
"files": [
"**/__tests__/*.{j,t}s?(x)",
"**/tests/unit/**/*.spec.{j,t}s?(x)"
],
"env": {
"jest": true,
"jest/globals": true
}
}
]
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
module.exports = {
plugins: [require("tailwindcss")],
};
\ No newline at end of file
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
<template>
<div data-test="app">
<app-header
:logoIcon="icon"
:logoImage="logo"
:cartIcon="cart"
:cartItems="cartItems"
:cartSubtotal="cartSubtotal"
@onClickLogo="onClickLogo"
@openDrawer="openDrawer"
/>
<main data-test="product-list" class="p-8 mx-auto">
<div
class="grid md:grid-cols-3 sm:grid-cols-2 grid-cols-1 justify-items-center gap-8"
>
<single-product
data-test="single-product"
v-for="product in products"
:product="product"
:key="product.pid"
:cartItems="cartItems"
@addItemToCart="addItemToCart"
@removeItemFromCart="removeItemFromCart"
@onClickProductTile="onClickProductTile"
/>
</div>
</main>
<side-drawer
:isDrawerOpen="drawerStatus"
:cartItems="cartItems"
:cartSubtotal="cartSubtotal"
@closeDrawer="closeDrawer"
@increaseQuantity="increaseQuantity"
@decreaseQuantity="decreaseQuantity"
/>
</div>
</template>
<script>
import { productList } from "./assets/dummy-data";
// Components
import AppHeader from "./components/Header.vue";
import SideDrawer from "./components/SideDrawer.vue";
import SingleProduct from "./components/Product.vue";
export default {
name: "App",
data: function () {
return {
icon: require("./assets/ws_logo_icon.png"),
logo: require("./assets/ws_horizontal.svg"),
cart: require("./assets/grocery-store.png"),
drawerStatus: false,
cartItems: [],
products: Array.from(productList)
};
},
methods: {
onClickLogo() {
console.log("Clicked on logo, route to home!");
},
openDrawer() {
this.drawerStatus = true;
},
closeDrawer() {
this.drawerStatus = false;
},
increaseQuantity(itemId) {
const item = this.cartItems.find((i) => i.pid === itemId);
if (item) {
item.quantity++;
}
},
decreaseQuantity(itemId) {
const item = this.cartItems.find((i) => i.pid === itemId);
if (item && item.quantity > 1) {
item.quantity--;
} else {
this.cartItems = [...this.cartItems].filter((i) => i.pid !== itemId);
}
},
addItemToCart(product) {
this.cartItems.push({ ...product, quantity: 1 });
},
removeItemFromCart(product) {
this.cartItems = [...this.cartItems].filter((i) => i.pid !== product.pid);
},
onClickProductTile(product) {
console.log("Clicked on product tile, route to product detail!", product);
// this.$router.push(`/product-detail/${this.product.pid}`);
},
},
computed: {
cartSubtotal() {
return this.cartItems.reduce(
(total, item) => total + item.price * item.quantity,
0
);
},
},
components: {
AppHeader,
SideDrawer,
SingleProduct,
},
};
</script>
import { shallowMount } from "@vue/test-utils";
import App from "../App.vue";
import AppHeader from "../components/Header.vue";
import SideDrawer from "../components/SideDrawer.vue";
import SingleProduct from "../components/Product.vue";
describe("App.vue", () => {
it("renders app correctly", () => {
const wrapper = shallowMount(App, {
components: { AppHeader, SingleProduct, SideDrawer },
stubs: ["router-view"],
});
expect(wrapper.find('[data-test="app"]').exists()).toBe(true);
});
});
\ No newline at end of file
import * as productList from "./products.json";
export { productList };
[
{
"price": 59.95,
"pid": "apilco-porcelain-ramekin",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0051/img76c.jpg",
"title": "Apilco Porcelain Ramekins"
},
{
"price": 79.95,
"pid": "apilco-porcelain-oval-au-gratin-baker",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0052/img29c.jpg",
"title": "Apilco Porcelain Au Gratin Bakers"
},
{
"price": 119.95,
"pid": "pillivuyt-coupe-porcelain-soup-and-pasta-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0007/img1c.jpg",
"title": "Pillivuyt Coupe Porcelain Soup/Pasta Plates"
},
{
"price": 107.95,
"pid": "pillivuyt-coupe-porcelain-cereal-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0006/img36c.jpg",
"title": "Pillivuyt Coupe Porcelain Cereal Bowls"
},
{
"price": 119.95,
"pid": "pillivuyt-coupe-porcelain-dinner-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0002/img91c.jpg",
"title": "Pillivuyt Coupe Porcelain Dinner Plates"
},
{
"price": 119.95,
"pid": "pillivuyt-coupe-porcelain-dinnerware-collection",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0005/img32c.jpg",
"title": "Pillivuyt Coupe Porcelain Dinnerware Collection"
},
{
"price": 107.95,
"pid": "pillivuyt-beaded-salad-plates",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202329/0055/img49c.jpg",
"title": "Pillivuyt Beaded Coupe Salad Plates"
},
{
"price": 129.95,
"pid": "pillivuyt-shallow-coupe-porcelain-serving-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0016/img11c.jpg",
"title": "Pillivuyt Coupe Porcelain Shallow Serving Bowl"
},
{
"price": 59.95,
"pid": "apilco-porcelain-souffle-dish",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202340/0455/img92c.jpg",
"title": "Apilco Porcelain Souffl\u00e9 Dishes"
},
{
"price": 119.95,
"pid": "pillivuyt-beaded-dinner-plates",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0022/img25c.jpg",
"title": "Pillivuyt Beaded Coupe Dinner Plates"
},
{
"price": 119.95,
"pid": "apilco-tradition-porcelain-dinnerware-collection",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0003/img1c.jpg",
"title": "Apilco Tradition Porcelain Dinnerware Collection"
},
{
"price": 119.95,
"pid": "apilco-tradition-porcelain-dinner-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0003/img33c.jpg",
"title": "Apilco Tradition Porcelain Dinner Plates"
},
{
"price": 79.95,
"pid": "apilco-tuileries-porcelain-salad-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0009/img80c.jpg",
"title": "Apilco Tuileries Porcelain Salad Serving Bowls"
},
{
"price": 89.95,
"pid": "gravy-boat-and-warming-base",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0033/img59c.jpg",
"title": "Pillivuyt Porcelain Gravy Boat with Warming Base"
},
{
"price": 107.95,
"pid": "pillivuyt-coupe-porcelain-salad-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0005/img10c.jpg",
"title": "Pillivuyt Coupe Porcelain Salad Plates"
},
{
"price": 107.95,
"pid": "pillivuyt-beaded-cereal-bowls",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202331/0044/img8c.jpg",
"title": "Pillivuyt Beaded Coupe Cereal Bowls"
},
{
"price": 69.95,
"pid": "pillivuyt-covered-butter-dish",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0023/img3c.jpg",
"title": "Pillivuyt Porcelain Covered Butter Dish"
},
{
"price": 89.95,
"pid": "apilco-zen-porcelain-platter",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0022/img85c.jpg",
"title": "Apilco Zen Porcelain Platters"
},
{
"price": 107.95,
"pid": "apilco-tradition-porcelain-cereal-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0016/img20c.jpg",
"title": "Apilco Tradition Porcelain Cereal Bowls"
},
{
"price": 149.95,
"pid": "pillivuyt-oval-porcelain-serving-platter",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0051/img15c.jpg",
"title": "Pillivuyt Oval Porcelain Serving Platters"
},
{
"price": 99.95,
"pid": "apilco-porcelain-deep-oval-roaster",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0051/img4c.jpg",
"title": "Apilco Porcelain Deep Oval Roasters"
},
{
"price": 67.95,
"pid": "pillivuyt-coupe-porcelain-bread-and-butter-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0033/img42c.jpg",
"title": "Pillivuyt Coupe Porcelain Appetizer Plates"
},
{
"price": 107.95,
"pid": "pillivuyt-plisse-cereal-bowls",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0035/img3c.jpg",
"title": "Pillivuyt Plisse Porcelain Cereal Bowls"
},
{
"price": 107.95,
"pid": "apilco-tradition-blue-banded-porcelain-cereal-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0016/img26c.jpg",
"title": "Apilco Tradition Blue-Banded Porcelain Cereal Bowls"
},
{
"price": 149.95,
"pid": "pillivuyt-porcelain-rectangular-roaster",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0023/img46c.jpg",
"title": "Pillivuyt Porcelain Rectangular Roasters"
},
{
"price": 107.95,
"pid": "apilco-tradition-blue-banded-porcelain-salad-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0013/img88c.jpg",
"title": "Apilco Tradition Blue-Banded Porcelain Salad Plates"
},
{
"price": 107.95,
"pid": "apilco-tradition-porcelain-salad-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0003/img86c.jpg",
"title": "Apilco Tradition Porcelain Salad Plates"
},
{
"price": 107.95,
"pid": "pillivuyt-coupe-porcelain-mug",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0005/img32c.jpg",
"title": "Pillivuyt Coupe Porcelain Mugs"
},
{
"price": 119.95,
"pid": "pillivuyt-plisse-dinner-plates",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0002/img85c.jpg",
"title": "Pillivuyt Plisse Porcelain Dinner Plates"
},
{
"price": 119.95,
"pid": "apilco-tradition-blue-banded-porcelain-dinner-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0014/img87c.jpg",
"title": "Apilco Tradition Blue-Banded Porcelain Dinner Plates"
},
{
"price": 119.95,
"pid": "apilco-tuileries-porcelain-dinner-plate",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0030/img77c.jpg",
"title": "Apilco Tuileries Porcelain Dinner Plates"
},
{
"price": 119.95,
"pid": "pillivuyt-perle-pasta-bowls",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0052/img18c.jpg",
"title": "Pillivuyt Perle Porcelain Pasta Bowls"
},
{
"price": 99.95,
"pid": "pillivuyt-coupe-porcelain-platter",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202326/0046/img95c.jpg",
"title": "Pillivuyt Coupe Porcelain Platter"
},
{
"price": 99.95,
"pid": "apilco-octagonal-porcelain-serving-platter",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0013/img8c.jpg",
"title": "Apilco Octagonal Porcelain Serving Platter"
},
{
"price": 139.95,
"pid": "pillivuyt-porcelain-cake-stand",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0021/img74c.jpg",
"title": "Pillivuyt Porcelain Cake Stands"
},
{
"price": 67.95,
"pid": "pillivuyt-beaded-bread-and-butter-plates",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202326/0060/img8c.jpg",
"title": "Pillivuyt Beaded Coupe Bread & Butter Plates"
},
{
"price": 119.95,
"pid": "pillivuyt-beaded-pasta-bowls",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202325/0024/img49c.jpg",
"title": "Pillivuyt Beaded Coupe Pasta Bowls, Set of 4"
},
{
"price": 119.95,
"pid": "pillivuyt-queen-anne-porcelain-cereal-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202322/0011/img30c.jpg",
"title": "Pillivuyt Queen Anne Porcelain Cereal Bowls"
},
{
"price": 159.95,
"pid": "pillivuyt-beaded-oval-platter",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202336/0066/img58c.jpg",
"title": "Pillivuyt Beaded Coupe Oval Platter"
},
{
"price": 129.95,
"pid": "pillivuyt-beaded-serving-bowl",
"thumb_image": "https://assets.wsimgs.com/wsimgs/rk/images/dp/wcm/202334/0077/img21c.jpg",
"title": "Pillivuyt Beaded Coupe Serving Bowl"
}
]
@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap");
@import "./tailwind.scss";
* {
font-family: Roboto, Arial, sans-serif;
}
.disable-scroll {
overflow: hidden;
}
\ No newline at end of file
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
\ No newline at end of file
<svg width="338" height="25" viewBox="0 0 338 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M34.7532 1.77755C34.4716 1.78806 34.1468 1.85114 33.7749 1.96678C33.4103 2.08243 33.0638 2.22961 32.7534 2.41535C32.3599 2.65364 32.0422 2.92699 31.8004 3.23888C31.5621 3.54727 31.3491 3.98181 31.1723 4.53551C30.3745 7.04466 29.4504 9.98134 28.3999 13.3351C27.3458 16.6888 26.2087 20.2668 24.9886 24.062H23.4436L17.4224 6.23514L11.163 24.0655H9.6757C8.56748 20.2597 7.41956 16.3068 6.23192 12.2136C5.04429 8.117 4.25013 5.37306 3.84221 3.98181C3.74114 3.64539 3.59314 3.34401 3.39821 3.08469C3.20327 2.82186 2.93615 2.58356 2.60043 2.36628C2.32248 2.18055 1.99398 2.04038 1.61856 1.94926C1.24314 1.85815 0.903812 1.79857 0.600586 1.77755V0.621094H10.3183V1.78105C9.46633 1.82661 8.74076 1.90721 8.14513 2.02636C7.5459 2.14901 7.24629 2.34876 7.24629 2.62911C7.24629 2.73775 7.26072 2.88143 7.29321 3.06016C7.32931 3.24238 7.35819 3.38606 7.37985 3.4947C7.63615 4.4514 8.09099 6.03539 8.74798 8.24316C9.40136 10.4509 10.376 13.7556 11.6611 18.1606L17.6137 0.950507H19.2562L25.2666 18.5251C26.0788 15.8232 26.7719 13.4612 27.3603 11.4392C27.9451 9.41713 28.4252 7.68947 28.8078 6.24916C29.0785 5.23639 29.2482 4.54252 29.3132 4.16755C29.3782 3.79257 29.4143 3.47367 29.4143 3.21435C29.4143 2.84639 29.1544 2.5345 28.6345 2.28568C28.1111 2.03337 27.2664 1.86516 26.104 1.77755V0.621094H34.7532V1.77755V1.77755Z" fill="#1A1A1A"/>
<path d="M47.0052 23.7711H36.2695V22.6147C36.5728 22.5937 37.0059 22.5621 37.5799 22.5166C38.1503 22.471 38.5546 22.4079 38.7892 22.3203C39.161 22.1802 39.4281 21.9874 39.5978 21.7421C39.7638 21.4968 39.8505 21.1569 39.8505 20.7223V3.95027C39.8505 3.56829 39.7891 3.24939 39.6664 2.99357C39.54 2.73775 39.2513 2.52398 38.7928 2.34876C38.4535 2.2191 38.0347 2.09645 37.5258 1.9808C37.0132 1.86515 36.598 1.79857 36.2731 1.77754V0.621094H47.0088V1.78105C46.6622 1.79156 46.2435 1.83362 45.767 1.9037C45.2869 1.97379 44.8645 2.06491 44.5072 2.17354C44.0776 2.30671 43.796 2.51697 43.648 2.80784C43.5036 3.10221 43.4314 3.42812 43.4314 3.78557V20.5401C43.4314 20.901 43.5145 21.2199 43.6769 21.4968C43.8393 21.7736 44.1137 21.9944 44.5072 22.1556C44.7418 22.2432 45.1281 22.3378 45.6551 22.4395C46.1857 22.5446 46.6406 22.6007 47.0088 22.6112V23.7711H47.0052Z" fill="#1A1A1A"/>
<path d="M69.0687 16.885L68.567 23.7711H49.9258V22.6147C50.1965 22.5937 50.5828 22.5551 51.0954 22.4991C51.6044 22.443 51.9617 22.3729 52.1603 22.2853C52.496 22.1451 52.7414 21.9383 52.8931 21.665C53.0483 21.3952 53.1205 21.0447 53.1205 20.6207V4.04489C53.1205 3.67693 53.0555 3.35102 52.9292 3.06716C52.7992 2.78331 52.5465 2.55552 52.1639 2.3803C51.9076 2.25064 51.5466 2.12098 51.0809 1.99482C50.6189 1.86866 50.2326 1.79507 49.9294 1.77404V0.621094H59.9972V1.78105C59.6832 1.79156 59.2789 1.84413 58.7771 1.94225C58.2789 2.04037 57.9216 2.12798 57.6941 2.20508C57.3151 2.33474 57.0552 2.55903 56.9144 2.87442C56.7736 3.18982 56.705 3.52624 56.705 3.88719V19.4362C56.705 20.1546 56.7411 20.7118 56.8133 21.1078C56.8855 21.5038 57.0588 21.8122 57.3295 22.0295C57.5858 22.2257 57.9685 22.3554 58.4811 22.4149C58.9901 22.4745 59.7012 22.5061 60.6217 22.5061C61.0368 22.5061 61.47 22.4955 61.9176 22.4745C62.3653 22.4535 62.7912 22.4079 63.1955 22.3449C63.589 22.2783 63.9464 22.1907 64.2785 22.075C64.6106 21.9629 64.856 21.8157 65.0113 21.644C65.4697 21.1429 66.0076 20.3859 66.614 19.3661C67.2277 18.3498 67.6501 17.5263 67.8847 16.8955H69.0687V16.885Z" fill="#1A1A1A"/>
<path d="M90.2878 16.885L89.786 23.7711H71.1484V22.6147C71.4192 22.5937 71.8054 22.5551 72.318 22.4991C72.8234 22.443 73.1808 22.3729 73.3829 22.2853C73.7186 22.1451 73.9677 21.9383 74.1157 21.665C74.2673 21.3952 74.3431 21.0447 74.3431 20.6207V4.04489C74.3431 3.67693 74.2782 3.35102 74.1482 3.06716C74.0219 2.78331 73.7656 2.55552 73.3829 2.3803C73.1266 2.25064 72.7656 2.12098 72.3 1.99482C71.8343 1.86866 71.4517 1.79507 71.1484 1.77404V0.621094H81.2163V1.78105C80.9022 1.79156 80.4979 1.84413 79.9961 1.94225C79.4944 2.04037 79.137 2.12798 78.9132 2.20508C78.5341 2.33474 78.2742 2.55903 78.1335 2.87442C77.9927 3.18982 77.9241 3.52624 77.9241 3.88719V19.4362C77.9241 20.1546 77.9602 20.7118 78.036 21.1078C78.1082 21.5038 78.2815 21.8122 78.545 22.0295C78.8049 22.2257 79.1875 22.3554 79.6965 22.4149C80.2055 22.4745 80.9202 22.5061 81.8408 22.5061C82.2559 22.5061 82.6891 22.4955 83.1367 22.4745C83.5843 22.4535 84.0103 22.4079 84.4146 22.3449C84.808 22.2783 85.169 22.1907 85.4975 22.075C85.8296 21.9629 86.0715 21.8157 86.2303 21.644C86.6888 21.1429 87.2266 20.3859 87.8331 19.3661C88.4467 18.3498 88.8691 17.5263 89.1037 16.8955H90.2878V16.885Z" fill="#1A1A1A"/>
<path d="M102.958 23.7711H92.2188V22.6147C92.522 22.5937 92.9551 22.5621 93.5291 22.5166C94.0995 22.471 94.5038 22.4079 94.7384 22.3203C95.1102 22.1802 95.3773 21.9874 95.5434 21.7421C95.7131 21.4968 95.7997 21.1569 95.7997 20.7223V3.95027C95.7997 3.56829 95.7383 3.24939 95.612 2.99357C95.4929 2.73775 95.2005 2.52398 94.742 2.34876C94.4027 2.2191 93.9803 2.09645 93.4714 1.9808C92.9624 1.86515 92.5472 1.79857 92.2224 1.77754V0.621094H102.962V1.78105C102.615 1.79156 102.196 1.83362 101.72 1.9037C101.236 1.97379 100.814 2.06491 100.456 2.17354C100.03 2.30671 99.7489 2.51697 99.6008 2.80784C99.4565 3.10221 99.3843 3.42812 99.3843 3.78557V20.5401C99.3843 20.901 99.4637 21.2199 99.6261 21.4968C99.7886 21.7736 100.067 21.9944 100.456 22.1556C100.695 22.2432 101.077 22.3378 101.608 22.4395C102.139 22.5446 102.59 22.6007 102.962 22.6112V23.7711H102.958Z" fill="#1A1A1A"/>
<path d="M130.077 23.7705H120.161V22.614C121.035 22.5615 121.76 22.4528 122.338 22.2881C122.912 22.1234 123.201 21.9237 123.201 21.6854C123.201 21.5872 123.19 21.4681 123.168 21.3244C123.143 21.1842 123.11 21.0581 123.063 20.9494L121.089 15.7594H112.718C112.407 16.5199 112.147 17.1822 111.952 17.7499C111.757 18.3176 111.584 18.8363 111.425 19.3164C111.281 19.786 111.18 20.1645 111.126 20.4553C111.068 20.7497 111.039 20.988 111.039 21.1737C111.039 21.6083 111.393 21.9482 112.1 22.1865C112.808 22.4283 113.598 22.5685 114.49 22.6105V23.767H105.509V22.6105C105.798 22.5895 106.162 22.5264 106.599 22.4213C107.036 22.3197 107.393 22.1795 107.675 22.0043C108.122 21.7099 108.469 21.405 108.714 21.0826C108.963 20.7637 109.202 20.3187 109.436 19.7544C110.635 16.8493 111.956 13.5902 113.4 9.96666C114.847 6.34311 116.136 3.11907 117.266 0.291016H118.609L126.558 20.2591C126.727 20.6831 126.919 21.0265 127.132 21.2859C127.345 21.5487 127.641 21.801 128.023 22.0533C128.28 22.2075 128.615 22.3337 129.03 22.4353C129.446 22.5404 129.792 22.5965 130.074 22.607V23.7705H130.077ZM120.482 14.3086L116.869 5.32333L113.306 14.3086H120.482Z" fill="#1A1A1A"/>
<path d="M161.705 23.7711H151.168V22.6147C151.55 22.6042 152.041 22.5656 152.64 22.4991C153.236 22.4325 153.651 22.3414 153.875 22.2222C154.225 22.0154 154.478 21.7806 154.64 21.5108C154.803 21.2445 154.882 20.9116 154.882 20.5086V3.67342H154.629L146.493 23.3962H145.655L137.909 3.26341H137.688V17.0813C137.688 18.4199 137.779 19.4362 137.948 20.1336C138.122 20.8275 138.389 21.3286 138.746 21.6335C138.992 21.8612 139.501 22.0785 140.277 22.2853C141.049 22.492 141.555 22.6007 141.789 22.6112V23.7676H132.158V22.6112C132.664 22.5656 133.194 22.485 133.747 22.3659C134.302 22.2467 134.728 22.068 135.032 21.8262C135.425 21.5213 135.692 21.0517 135.837 20.4209C135.985 19.7902 136.057 18.7353 136.057 17.2565V5.41861C136.057 4.73175 135.97 4.17455 135.801 3.7365C135.634 3.30196 135.393 2.94801 135.079 2.67467C134.732 2.38381 134.31 2.16303 133.801 2.02285C133.299 1.88268 132.801 1.80208 132.31 1.77754V0.621094H140.436L147.269 17.9994L153.099 3.46316C153.312 2.93049 153.492 2.37329 153.648 1.79156C153.796 1.20983 153.879 0.820844 153.889 0.624598H161.665V1.78455C161.351 1.79507 160.954 1.84413 160.467 1.93174C159.976 2.01935 159.618 2.09995 159.398 2.17705C159.019 2.31021 158.755 2.52398 158.625 2.82886C158.492 3.13375 158.423 3.46316 158.423 3.82411V20.5121C158.423 20.894 158.492 21.2129 158.625 21.4758C158.759 21.7351 159.019 21.9629 159.398 22.1591C159.6 22.2678 159.958 22.3694 160.474 22.4605C160.99 22.5516 161.398 22.6042 161.701 22.6182V23.7711H161.705Z" fill="#1A1A1A"/>
<path d="M179.478 13.1492C179.98 13.6924 180.355 14.2882 180.597 14.9365C180.836 15.5848 180.958 16.3382 180.958 17.1968C180.958 19.2434 180.179 20.929 178.623 22.2537C177.063 23.5818 175.132 24.2442 172.822 24.2442C171.757 24.2442 170.696 24.083 169.627 23.7641C168.562 23.4452 167.642 23.0562 166.873 22.5971L166.151 23.7886H164.808L164.573 15.8616H165.934C166.216 16.8394 166.544 17.7225 166.92 18.511C167.291 19.2995 167.79 20.0354 168.403 20.7222C168.988 21.3636 169.67 21.8752 170.446 22.2572C171.226 22.6356 172.129 22.8284 173.161 22.8284C173.934 22.8284 174.609 22.7303 175.186 22.5375C175.764 22.3413 176.229 22.0609 176.59 21.7035C176.948 21.3425 177.211 20.922 177.388 20.4384C177.565 19.9548 177.648 19.3941 177.648 18.7633C177.648 17.8381 177.381 16.9725 176.843 16.1735C176.305 15.3745 175.5 14.7648 174.439 14.3513C173.71 14.0709 172.876 13.759 171.934 13.4191C170.995 13.0792 170.179 12.7532 169.497 12.4519C168.154 11.8666 167.111 11.0957 166.364 10.146C165.62 9.19628 165.245 7.95222 165.245 6.4208C165.245 5.54119 165.432 4.71766 165.801 3.96071C166.169 3.19675 166.692 2.5169 167.378 1.92115C168.028 1.35694 168.793 0.911882 169.681 0.592982C170.566 0.270577 171.486 0.109375 172.454 0.109375C173.551 0.109375 174.533 0.274082 175.403 0.596486C176.269 0.922395 177.063 1.30437 177.778 1.73892L178.467 0.628026H179.81L179.944 8.31317H178.587C178.338 7.43357 178.06 6.58901 177.753 5.783C177.442 4.98049 177.045 4.24807 176.551 3.59625C176.071 2.96546 175.482 2.46083 174.785 2.08936C174.089 1.71439 173.24 1.52515 172.233 1.52515C171.165 1.52515 170.262 1.85807 169.511 2.5204C168.761 3.18273 168.385 3.99575 168.385 4.95245C168.385 5.95471 168.627 6.78525 169.107 7.44058C169.587 8.0994 170.288 8.63908 171.205 9.06311C172.024 9.44509 172.829 9.771 173.619 10.0514C174.41 10.3282 175.172 10.6261 175.912 10.9415C176.583 11.2218 177.233 11.5442 177.854 11.9052C178.478 12.2521 179.02 12.6726 179.478 13.1492Z" fill="#1A1A1A"/>
<path d="M206.631 13.0824C207.136 13.6256 207.504 14.2248 207.746 14.8696C207.991 15.5179 208.107 16.2714 208.107 17.13C208.107 19.1765 207.331 20.8586 205.771 22.1868C204.216 23.515 202.281 24.1773 199.974 24.1773C198.913 24.1773 197.844 24.0161 196.779 23.6972C195.718 23.3748 194.801 22.9858 194.025 22.5302L193.303 23.7182H191.96L191.726 15.7913H193.09C193.368 16.769 193.697 17.6521 194.072 18.4406C194.444 19.2291 194.942 19.965 195.559 20.6519C196.144 21.2932 196.823 21.8048 197.602 22.1868C198.378 22.5688 199.285 22.758 200.313 22.758C201.086 22.758 201.761 22.6599 202.338 22.4637C202.916 22.2674 203.389 21.9906 203.743 21.6296C204.1 21.2722 204.367 20.8481 204.544 20.361C204.714 19.8774 204.804 19.3202 204.804 18.6859C204.804 17.7607 204.533 16.8952 203.995 16.0962C203.458 15.2972 202.656 14.6909 201.591 14.2739C200.862 13.9935 200.032 13.6816 199.086 13.3382C198.144 12.9983 197.335 12.6759 196.653 12.371C195.307 11.7822 194.263 11.0148 193.52 10.0616C192.772 9.11189 192.401 7.86783 192.401 6.33641C192.401 5.45681 192.585 4.63327 192.957 3.87282C193.328 3.11236 193.852 2.43251 194.538 1.83326C195.187 1.26905 195.956 0.823991 196.841 0.505091C197.729 0.186191 198.653 0.0214844 199.617 0.0214844C200.714 0.0214844 201.696 0.186191 202.566 0.5121C203.436 0.838009 204.226 1.21999 204.945 1.65453L205.634 0.54364H206.977L207.111 8.22878H205.746C205.501 7.34918 205.223 6.50462 204.916 5.69861C204.609 4.8961 204.208 4.16368 203.714 3.51186C203.234 2.88107 202.645 2.37644 201.949 2.00497C201.256 1.63 200.404 1.44077 199.393 1.44077C198.328 1.44077 197.422 1.77368 196.671 2.43601C195.92 3.09835 195.545 3.90786 195.545 4.86456C195.545 5.86682 195.79 6.69736 196.267 7.35619C196.75 8.01151 197.451 8.55469 198.368 8.97873C199.183 9.36071 199.988 9.68661 200.779 9.96697C201.57 10.2438 202.335 10.5417 203.071 10.8571C203.743 11.1409 204.389 11.4633 205.013 11.8208C205.627 12.1888 206.169 12.6058 206.631 13.0824Z" fill="#1A1A1A"/>
<path d="M229.982 3.29413C231.033 4.35947 231.859 5.64559 232.451 7.15248C233.043 8.65937 233.343 10.324 233.343 12.1533C233.343 13.9896 233.04 15.6612 232.433 17.161C231.831 18.6609 230.989 19.94 229.914 20.9948C228.874 22.0392 227.661 22.8452 226.282 23.4094C224.903 23.9736 223.438 24.2574 221.878 24.2574C220.221 24.2574 218.687 23.9561 217.283 23.3533C215.879 22.7506 214.673 21.9095 213.659 20.8336C212.651 19.7788 211.861 18.4962 211.28 16.9928C210.702 15.4859 210.417 13.8739 210.417 12.1568C210.417 10.2749 210.72 8.59629 211.323 7.12094C211.933 5.64909 212.763 4.37349 213.828 3.29413C214.879 2.2288 216.106 1.41227 217.499 0.848064C218.893 0.280352 220.355 0 221.875 0C223.456 0 224.947 0.287361 226.344 0.865587C227.751 1.44031 228.961 2.24982 229.982 3.29413ZM227.473 19.7087C228.102 18.7205 228.56 17.5991 228.842 16.348C229.13 15.0969 229.271 13.6987 229.271 12.1568C229.271 10.5658 229.109 9.10793 228.791 7.78327C228.473 6.4551 228.004 5.32318 227.39 4.39101C226.773 3.46585 226.001 2.74394 225.069 2.2288C224.142 1.71365 223.077 1.45433 221.875 1.45433C220.532 1.45433 219.391 1.7522 218.445 2.35145C217.503 2.9507 216.738 3.74971 216.142 4.75196C215.586 5.70867 215.164 6.83007 214.893 8.11268C214.615 9.39529 214.478 10.7445 214.478 12.1603C214.478 13.7267 214.626 15.139 214.915 16.4006C215.207 17.6622 215.666 18.7836 216.294 19.7613C216.9 20.718 217.658 21.4679 218.579 22.0041C219.499 22.5438 220.597 22.8101 221.871 22.8101C223.073 22.8101 224.152 22.5368 225.116 21.9936C226.084 21.4469 226.871 20.6865 227.473 19.7087Z" fill="#1A1A1A"/>
<path d="M258.909 1.71464C258.598 1.72516 258.118 1.81277 257.465 1.97397C256.815 2.13868 256.349 2.30689 256.071 2.48211C255.667 2.75545 255.396 3.27761 255.259 4.04857C255.118 4.81954 255.046 5.80077 255.046 6.98526V23.936H253.584L239.134 4.99476V16.9378C239.134 18.2764 239.217 19.3032 239.394 20.0216C239.571 20.74 239.834 21.2517 240.195 21.5566C240.452 21.7984 240.986 22.0191 241.791 22.2259C242.6 22.4326 243.127 22.5413 243.39 22.5518V23.7083H233.607V22.5518C233.911 22.5308 234.416 22.4221 235.138 22.2329C235.856 22.0437 236.3 21.8684 236.481 21.7178C236.874 21.4129 237.138 20.9468 237.286 20.323C237.434 19.6957 237.506 18.6269 237.506 17.1165V5.70966C237.506 5.21203 237.416 4.7109 237.239 4.20978C237.058 3.71215 236.817 3.32316 236.517 3.05332C236.113 2.69237 235.564 2.38749 234.874 2.13167C234.185 1.87585 233.629 1.73567 233.203 1.71464V0.558192H240.018L253.425 18.2063V7.19202C253.425 5.84282 253.335 4.80903 253.155 4.08362C252.974 3.36171 252.718 2.8781 252.379 2.6398C252.068 2.43305 251.552 2.23329 250.841 2.03705C250.13 1.8408 249.588 1.73217 249.216 1.71114V0.554688H258.912V1.71464H258.909Z" fill="#1A1A1A"/>
<path d="M278.243 3.29413C279.297 4.35947 280.12 5.64559 280.716 7.15248C281.308 8.65937 281.604 10.324 281.604 12.1533C281.604 13.9896 281.304 15.6612 280.698 17.161C280.092 18.6609 279.254 19.94 278.178 20.9948C277.135 22.0392 275.926 22.8452 274.547 23.4094C273.168 23.9736 271.702 24.2574 270.143 24.2574C268.486 24.2574 266.952 23.9561 265.548 23.3533C264.14 22.7506 262.934 21.9095 261.927 20.8336C260.92 19.7788 260.126 18.4962 259.548 16.9928C258.97 15.4859 258.682 13.8739 258.682 12.1568C258.682 10.2749 258.985 8.59629 259.591 7.12094C260.194 5.64909 261.028 4.37349 262.097 3.29413C263.151 2.2288 264.371 1.41227 265.768 0.848064C267.165 0.280352 268.62 0 270.143 0C271.724 0 273.215 0.287361 274.615 0.865587C276.012 1.44031 277.225 2.24982 278.243 3.29413ZM275.742 19.7087C276.37 18.7205 276.825 17.5991 277.11 16.348C277.395 15.0969 277.539 13.6987 277.539 12.1568C277.539 10.5658 277.381 9.10793 277.063 7.78327C276.738 6.4551 276.272 5.32318 275.655 4.39101C275.038 3.46585 274.269 2.74394 273.338 2.2288C272.406 1.71365 271.341 1.45433 270.143 1.45433C268.8 1.45433 267.656 1.7522 266.714 2.35145C265.775 2.9507 265.002 3.74971 264.41 4.75196C263.851 5.70867 263.436 6.83007 263.158 8.11268C262.887 9.39529 262.746 10.7445 262.746 12.1603C262.746 13.7267 262.887 15.139 263.179 16.4006C263.476 17.6622 263.934 18.7836 264.558 19.7613C265.161 20.718 265.927 21.4679 266.843 22.0041C267.764 22.5438 268.861 22.8101 270.139 22.8101C271.338 22.8101 272.421 22.5368 273.381 21.9936C274.352 21.4469 275.135 20.6865 275.742 19.7087Z" fill="#1A1A1A"/>
<path d="M311.304 23.7047H300.767V22.5483C301.146 22.5343 301.637 22.4992 302.236 22.4327C302.836 22.3661 303.247 22.275 303.475 22.1558C303.821 21.949 304.074 21.7142 304.236 21.4479C304.399 21.1781 304.482 20.8452 304.482 20.4422V3.60351H304.229L296.096 23.3298H295.255L287.508 3.197H287.292V17.0148C287.292 18.3535 287.378 19.3698 287.552 20.0672C287.721 20.7611 287.988 21.2657 288.349 21.5671C288.595 21.7948 289.104 22.0121 289.876 22.2189C290.649 22.4256 291.154 22.5343 291.389 22.5448V23.7012H281.758V22.5448C282.26 22.4992 282.79 22.4186 283.346 22.2995C283.902 22.1803 284.328 22.0016 284.628 21.7633C285.021 21.4584 285.288 20.9923 285.436 20.3615C285.581 19.7308 285.653 18.6759 285.653 17.1971V5.35221C285.653 4.66885 285.573 4.10815 285.404 3.6701C285.238 3.23555 284.992 2.88161 284.682 2.60827C284.335 2.3139 283.909 2.09662 283.408 1.95645C282.902 1.81627 282.4 1.73217 281.909 1.71114V0.554688H290.042L296.872 17.933L302.706 3.39675C302.915 2.86409 303.099 2.30689 303.251 1.72165C303.402 1.13992 303.482 0.750934 303.496 0.554688H311.272V1.71114C310.958 1.72165 310.557 1.77071 310.07 1.85832C309.582 1.94593 309.229 2.02654 309.005 2.10363C308.622 2.23329 308.366 2.45057 308.232 2.75545C308.099 3.06033 308.03 3.39325 308.03 3.7507V20.4422C308.03 20.8241 308.099 21.143 308.232 21.4059C308.366 21.6652 308.626 21.8965 309.005 22.0927C309.203 22.2014 309.561 22.303 310.081 22.3941C310.597 22.4887 311.005 22.5378 311.308 22.5518V23.7047H311.304Z" fill="#1A1A1A"/>
<path d="M337.4 23.7045H327.487V22.548C328.364 22.492 329.086 22.3833 329.664 22.2221C330.241 22.0574 330.53 21.8577 330.53 21.6194C330.53 21.5212 330.519 21.4021 330.498 21.2584C330.476 21.1182 330.443 20.9921 330.396 20.8834L328.422 15.6969H320.054C319.737 16.4574 319.484 17.1232 319.289 17.6874C319.094 18.2551 318.914 18.7773 318.758 19.2539C318.61 19.7235 318.509 20.102 318.455 20.3963C318.401 20.6872 318.372 20.929 318.372 21.1147C318.372 21.5493 318.722 21.8857 319.426 22.124C320.134 22.3623 320.932 22.506 321.812 22.548V23.7045H312.831V22.548C313.12 22.527 313.484 22.4639 313.925 22.3588C314.362 22.2572 314.723 22.117 315.001 21.9418C315.448 21.6474 315.798 21.3425 316.04 21.0201C316.289 20.6977 316.531 20.2562 316.762 19.6919C317.961 16.7868 319.282 13.5242 320.729 9.90416C322.173 6.28061 323.462 3.05657 324.592 0.228516H325.935L333.887 20.1966C334.053 20.6206 334.245 20.964 334.458 21.2234C334.671 21.4827 334.967 21.742 335.349 21.9908C335.609 22.145 335.945 22.2712 336.36 22.3728C336.771 22.4779 337.118 22.534 337.4 22.5445V23.7045V23.7045ZM327.808 14.2426L324.195 5.26083L320.632 14.2426H327.808Z" fill="#1A1A1A"/>
</svg>
<template>
<header
data-test="header"
class="flex justify-between h-14 border-b border-gray-500 px-8"
>
<div
class="flex-1 flex items-center max-w-fit cursor-pointer"
@click="$emit('onClickLogo')"
>
<img
class="w-10 rounded"
:src="logoIcon"
alt="William Sonoma Logo Icon"
/>
<img class="ml-3" :src="logoImage" alt="William Sonoma Logo" />
</div>
<div class="flex-1 flex justify-end items-center">
<button class="flex" @click="$emit('openDrawer')">
<img class="w-6 mr-2" :src="cartIcon" alt="Cart Icon" />
<span>({{ cartItems.length }})</span>
</button>
</div>
</header>
</template>
<script>
export default {
name: "app-header",
props: ["logoIcon", "logoImage", "cartIcon", "cartItems"],
};
</script>
<template>
<div
data-test="product-container"
:key="product.pid"
class="cursor-pointer w-full"
>
<div class="w-full flex justify-center relative">
<img
:class="imgClass"
:src="product.thumb_image"
:alt="product.title"
@click="$emit('onClickProductTile', product)"
/>
<button
class="w-full flex justify-center items-center py-3 bg-black/50 absolute bottom-0"
@click="
!isSelected
? $emit('addItemToCart', product)
: $emit('removeItemFromCart', product)
"
>
<span class="uppercase text-white">
{{ isSelected ? "- Remove from" : "+ Add to" }} cart
</span>
</button>
</div>
<div class="py-2" @click="$emit('onClickProductTile', product)">
<h3 class="font-bold text-xl mb-1">{{ product.title }}</h3>
<p class="text-gray-900 mb-1 text-sm">{{ product.description }}</p>
<p class="text-gray-900 font-bold text-base">${{ product.price }}</p>
</div>
</div>
</template>
<script>
export default {
name: "single-product",
props: ["product", "cartItems", "imgClass"],
computed: {
isSelected() {
return this.cartItems.find((item) => item.pid === this.product.pid);
},
},
};
</script>
<template>
<transition name="slide" mode="out-in">
<div
data-test="side-drawer-container"
:class="isDrawerOpen ? 'block' : 'hidden'"
>
<div
data-test="side-drawer-overlay"
:class="isDrawerOpen ? containerClasses : 'w-0'"
@click="$emit('closeDrawer')"
></div>
<div class="w-1/3 h-full absolute top-0 right-0">
<div class="bg-white h-screen p-4">
<h2 class="font-bold text-2xl mb-4">Your Cart</h2>
<ul>
<li
v-for="item in cartItems"
:key="item.pid"
class="flex items-center justify-between p-2 border-b border-gray-300"
>
<div class="flex items-center">
<span class="text-base font-medium">{{ item.title }}</span>
<span class="text-gray-600 ml-2">{{
formatCurrency(item.price)
}}</span>
</div>
<div class="flex items-center">
<button
@click="$emit('decreaseQuantity', item.pid)"
class="text-red-500 p-2"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
class="h-4 w-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M18 12H6"
/>
</svg>
</button>
<span class="text-lg font-medium">{{ item.quantity }}</span>
<button
@click="$emit('increaseQuantity', item.pid)"
class="text-green-500 p-2"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
class="h-4 w-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
/>
</svg>
</button>
</div>
<span class="text-gray-600"
>Subtotal:
{{ formatCurrency(item.price * item.quantity) }}</span
>
</li>
</ul>
<p v-if="!cartItems.length" class="mt-2 text-gray-500">
Please add items to your cart.
</p>
<div class="mt-4 flex justify-end">
<p class="text-lg font-semibold">
Total: {{ formatCurrency(cartSubtotal) }}
</p>
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
const containerClasses = "bg-black w-full h-full absolute top-0 opacity-60";
export default {
name: "side-drawer",
data: function () {
return { containerClasses };
},
props: ["isDrawerOpen", "cartItems", "cartSubtotal"],
methods: {
formatCurrency(amount) {
return `$${amount.toFixed(2)}`;
},
},
};
</script>
<style scoped>
.slide-enter-active,
.slide-leave-active {
transition: transform 0.3s;
}
.slide-enter,
.slide-leave-to {
transform: translateX(-100%);
}
</style>
import { shallowMount } from "@vue/test-utils";
import { productList } from "../../assets/dummy-data";
import AppHeader from "../Header.vue";
describe("AppHeader.vue", () => {
const productArray = Object.values(productList).filter(
(item) => typeof item === "object"
);
const propsData = {
logoIcon: require("../../assets/ws_logo_icon.png"),
logoImage: require("../../assets/ws_horizontal.svg"),
cartIcon: require("../../assets/grocery-store.png"),
cartItems: [productArray[0], productArray[2], productArray[3]],
};
const listeners = {
onClickLogo: jest.fn(),
openDrawer: jest.fn(),
};
it("renders header correctly", () => {
const wrapper = shallowMount(AppHeader, { propsData, listeners });
expect(wrapper.find('[data-test="header"]').exists()).toBe(true);
});
it('calls store action "openDrawer" when cart icon is clicked', () => {
const wrapper = shallowMount(AppHeader, { propsData, listeners });
const button = wrapper.find("button");
button.trigger("click");
expect(listeners.openDrawer).toHaveBeenCalled();
});
});
import { shallowMount } from "@vue/test-utils";
import { productList } from "../../assets/dummy-data";
import Product from "../Product.vue";
describe("Product.vue", () => {
const productArray = Object.values(productList).filter(
(item) => typeof item === "object"
);
const propsData = {
product: productArray[0],
cartItems: [productArray[0], productArray[2], productArray[3]],
};
const listeners = {
onClickProductTile: jest.fn(),
addItemToCart: jest.fn(),
removeItemFromCart: jest.fn(),
onClickProductTile: jest.fn(),
};
it("renders product correctly", () => {
const wrapper = shallowMount(Product, {
propsData,
listeners,
computed: {
isSelected: jest.fn().mockReturnValue(true),
},
});
expect(wrapper.find('[data-test="product-container"]').exists()).toBe(true);
});
it("renders product correctly", () => {
const wrapper = shallowMount(Product, {
propsData: { ...propsData, cartItems: [] },
listeners,
computed: {
isSelected: jest.fn().mockReturnValue(false),
},
});
expect(wrapper.find('[data-test="product-container"]').exists()).toBe(true);
});
it('calls store action "removeItemFromCart" when "Remove from Cart" button is clicked', () => {
const wrapper = shallowMount(Product, {
propsData,
listeners,
computed: {
isSelected: jest.fn().mockReturnValue(true),
},
});
const button = wrapper.find("button");
button.trigger("click");
expect(listeners.removeItemFromCart).toHaveBeenCalled();
});
it('calls store action "addItemToCart" when "Add to Cart" button is clicked', () => {
const wrapper = shallowMount(Product, {
propsData: { ...propsData, cartItems: [] },
listeners,
computed: {
isSelected: jest.fn().mockReturnValue(false),
},
});
const button = wrapper.find("button");
button.trigger("click");
expect(listeners.addItemToCart).toHaveBeenCalled();
});
});
import { shallowMount } from "@vue/test-utils";
import { productList } from "../../assets/dummy-data";
import SideDrawer from "../SideDrawer.vue";
describe("SideDrawer.vue", () => {
const productArray = Object.values(productList).filter(
(item) => typeof item === "object"
);
const propsData = {
isDrawerOpen: true,
cartItems: [productArray[0], productArray[2], productArray[3]],
cartSubtotal: 0,
};
const listeners = {
closeDrawer: jest.fn(),
};
const containerClasses = "bg-black w-full h-full absolute top-0 opacity-60";
it("renders SideDrawer correctly", () => {
const wrapper = shallowMount(SideDrawer, {
propsData,
listeners,
data: function () {
return { containerClasses };
},
});
expect(wrapper.find('[data-test="side-drawer-container"]').exists()).toBe(
true
);
});
it('calls store action "closeDrawer" when "Drawer Overlay" is clicked', () => {
const wrapper = shallowMount(SideDrawer, {
propsData,
listeners,
data: function () {
return { containerClasses };
},
});
const overlay = wrapper.find('[data-test="side-drawer-overlay"]');
overlay.trigger("click");
expect(listeners.closeDrawer).toHaveBeenCalled();
});
});
import Vue from "vue";
import App from "./App.vue";
// Stylesheet
import "./assets/scss/style.scss";
Vue.config.productionTip = false;
new Vue({
render: (h) => h(App),
}).$mount("#app");
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
const { defineConfig } = require("@vue/cli-service");
const federationConfig = require("./federationConfig.json");
module.exports = defineConfig({
publicPath: "http://localhost:8081/",
transpileDependencies: true,
devServer: {
port: 8081,
},
chainWebpack: (config) => {
config.optimization.delete("splitChunks");
config
.plugin("module-federation-plugin")
.use(require("webpack").container.ModuleFederationPlugin, [
{
...federationConfig,
shared: {
vue: {
eager: true,
singleton: false,
},
},
filename: "remoteEntry.js",
},
]);
},
});
module.exports = {
module: {
rules: [
// ... other rules omitted
// this will apply to both plain `.scss` files
// AND `<style lang="scss">` blocks in `.vue` files
{
test: /\.scss$/,
use: ["vue-style-loader", "css-loader", "sass-loader"],
},
],
},
// plugin omitted
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment