├── src ├── index.css ├── components │ ├── App │ │ ├── index.js │ │ ├── Content │ │ │ ├── index.js │ │ │ ├── component.css │ │ │ ├── customerPages.js │ │ │ └── component.jsx │ │ ├── Footer │ │ │ ├── index.js │ │ │ ├── component.css │ │ │ └── component.jsx │ │ ├── Theme │ │ │ ├── index.js │ │ │ └── component.jsx │ │ ├── Navigation │ │ │ ├── index.js │ │ │ ├── Categories │ │ │ │ ├── index.js │ │ │ │ ├── query-container.jsx │ │ │ │ └── component.jsx │ │ │ ├── CustomerLogin │ │ │ │ ├── index.js │ │ │ │ ├── redux-container.jsx │ │ │ │ └── component.jsx │ │ │ ├── QuickSearch │ │ │ │ ├── index.js │ │ │ │ ├── redux-container.jsx │ │ │ │ └── component.jsx │ │ │ ├── MiniCart.js │ │ │ └── component.jsx │ │ ├── component.test.js │ │ └── component.jsx │ ├── Test │ │ └── Debug │ │ │ ├── index.js │ │ │ ├── component.css │ │ │ └── component.js │ ├── Pages │ │ ├── HomePage │ │ │ ├── index.js │ │ │ ├── component.css │ │ │ └── component.jsx │ │ ├── CartPage │ │ │ ├── index.js │ │ │ ├── Empty │ │ │ │ ├── index.js │ │ │ │ └── component.jsx │ │ │ ├── PriceBox │ │ │ │ ├── index.js │ │ │ │ └── component.jsx │ │ │ ├── component.css │ │ │ ├── redux-container.jsx │ │ │ ├── CartTotals.jsx │ │ │ └── component.jsx │ │ ├── ErrorPage │ │ │ ├── index.js │ │ │ └── component.jsx │ │ ├── Page │ │ │ ├── index.js │ │ │ └── query-container.jsx │ │ ├── SearchPage │ │ │ ├── index.js │ │ │ ├── EmptySearchResults.jsx │ │ │ ├── SearchPageViaQuery.jsx │ │ │ ├── component.jsx │ │ │ └── SearchPageViaElasticSearch.jsx │ │ ├── CheckoutPage │ │ │ ├── index.js │ │ │ └── component.jsx │ │ ├── CmsPage │ │ │ ├── index.js │ │ │ ├── query-container.jsx │ │ │ └── component.jsx │ │ ├── DownloadsPage │ │ │ ├── index.js │ │ │ └── component.jsx │ │ ├── LoginPage │ │ │ ├── index.js │ │ │ ├── redux-container.jsx │ │ │ └── component.jsx │ │ ├── LogoutPage │ │ │ ├── index.js │ │ │ ├── component.jsx │ │ │ └── redux-container.jsx │ │ ├── NotFoundPage │ │ │ ├── index.js │ │ │ └── component.jsx │ │ ├── WishlistPage │ │ │ ├── index.js │ │ │ └── component.jsx │ │ ├── CategoryPage │ │ │ ├── index.js │ │ │ ├── component.jsx │ │ │ └── query-container.jsx │ │ ├── CustomerPage │ │ │ ├── Address │ │ │ │ ├── View │ │ │ │ │ ├── index.js │ │ │ │ │ └── component.jsx │ │ │ │ ├── index.js │ │ │ │ ├── Edit │ │ │ │ │ ├── index.js │ │ │ │ │ ├── redux-container.jsx │ │ │ │ │ └── component.jsx │ │ │ │ └── component.jsx │ │ │ ├── Dashboard │ │ │ │ ├── index.js │ │ │ │ └── component.jsx │ │ │ ├── index.js │ │ │ ├── Account │ │ │ │ ├── Edit │ │ │ │ │ ├── index.js │ │ │ │ │ └── component.jsx │ │ │ │ ├── ChangePassword │ │ │ │ │ ├── index.js │ │ │ │ │ └── component.jsx │ │ │ │ └── Create │ │ │ │ │ ├── index.js │ │ │ │ │ ├── redux-container.jsx │ │ │ │ │ └── component.jsx │ │ │ ├── Orders │ │ │ │ ├── index.js │ │ │ │ ├── Order │ │ │ │ │ ├── index.jsx │ │ │ │ │ └── component.jsx │ │ │ │ ├── query-container.jsx │ │ │ │ └── component.jsx │ │ │ ├── component.css │ │ │ ├── component.jsx │ │ │ └── redux-container.jsx │ │ └── ProductPage │ │ │ ├── index.js │ │ │ ├── component.jsx │ │ │ └── query-container.jsx │ ├── Utils │ │ └── Loading │ │ │ ├── index.js │ │ │ └── component.jsx │ ├── Atoms │ │ └── Product │ │ │ ├── Price │ │ │ ├── index.js │ │ │ └── component.jsx │ │ │ ├── StockStatus │ │ │ ├── index.js │ │ │ └── component.jsx │ │ │ └── AddToCart │ │ │ ├── index.js │ │ │ ├── component.jsx │ │ │ └── redux-container.jsx │ └── Molecules │ │ ├── ProductGrid │ │ ├── index.js │ │ ├── Item │ │ │ ├── index.js │ │ │ └── component.jsx │ │ └── component.jsx │ │ ├── CustomerMenu │ │ ├── index.js │ │ └── component.jsx │ │ ├── CmsBlock │ │ ├── index.js │ │ ├── component.jsx │ │ └── query-container.jsx │ │ ├── Messages │ │ ├── Item │ │ │ ├── index.js │ │ │ └── component.jsx │ │ ├── index.js │ │ ├── component.jsx │ │ └── redux-container.jsx │ │ └── CustomerLoginForm │ │ ├── index.js │ │ ├── redux-container.jsx │ │ └── component.jsx ├── react-app-env.d.ts ├── styles │ ├── _typography.scss │ └── _product-grid.scss ├── state │ ├── graphql │ │ ├── mutations │ │ │ ├── createEmptyCart.graphql │ │ │ ├── generateCustomerToken.graphql │ │ │ ├── changeCustomerPassword.graphql │ │ │ ├── removeCartItem.graphql │ │ │ ├── updateCustomer.graphql │ │ │ ├── createCustomer.graphql │ │ │ ├── updateProductInCart.graphql │ │ │ ├── addSimpleProductToCart.graphql │ │ │ ├── saveCustomer.graphql │ │ │ └── updateCustomerAddress.graphql │ │ ├── queries │ │ │ ├── resolveCatalogUrlToId.graphql │ │ │ ├── cmsPage.graphql │ │ │ ├── customerOrders.graphql │ │ │ ├── cmsBlock.graphql │ │ │ ├── byAttribute.graphql-example │ │ │ ├── topLevelCategories.graphql │ │ │ ├── customProductAttribute.graphql │ │ │ ├── customer.graphql │ │ │ ├── search.graphql │ │ │ ├── cart.graphql │ │ │ ├── categoryPage.graphql │ │ │ ├── productPage.graphql │ │ │ └── cartFull.graphql │ │ └── apollo-client.js │ └── redux │ │ ├── ducks │ │ ├── common │ │ │ ├── initialState.js │ │ │ ├── reducers │ │ │ │ ├── unlock.js │ │ │ │ └── lock.js │ │ │ ├── types.js │ │ │ ├── actions.js │ │ │ ├── middleware │ │ │ │ └── unlock.js │ │ │ ├── index.js │ │ │ ├── middleware.js │ │ │ └── reducer.js │ │ ├── messages │ │ │ ├── initialState.js │ │ │ ├── types.js │ │ │ ├── index.js │ │ │ ├── actions.js │ │ │ └── reducer.js │ │ ├── cart │ │ │ ├── reducers │ │ │ │ ├── updateCart.js │ │ │ │ ├── updateProduct.js │ │ │ │ ├── setCartId.js │ │ │ │ ├── setCart.js │ │ │ │ ├── addProduct.js │ │ │ │ └── removeCartItem.js │ │ │ ├── initialState.js │ │ │ ├── index.js │ │ │ ├── types.js │ │ │ ├── middleware │ │ │ │ ├── getCartId.js │ │ │ │ ├── updateCart.js │ │ │ │ ├── updateProduct.js │ │ │ │ ├── removeCartItem.js │ │ │ │ └── addToCart.js │ │ │ ├── actions.js │ │ │ ├── middleware.js │ │ │ └── reducer.js │ │ ├── customer │ │ │ ├── initialState.js │ │ │ ├── reducers │ │ │ │ ├── setCustomerData.js │ │ │ │ ├── setCustomerToken.js │ │ │ │ └── postLogoutCustomer.js │ │ │ ├── index.js │ │ │ ├── middleware │ │ │ │ ├── logoutCustomer.js │ │ │ │ ├── setCustomerToken.js │ │ │ │ ├── saveAddress.js │ │ │ │ ├── saveCustomer.js │ │ │ │ ├── loginCustomer.js │ │ │ │ └── createCustomer.js │ │ │ ├── reducer.js │ │ │ ├── types.js │ │ │ ├── middleware.js │ │ │ └── actions.js │ │ └── search │ │ │ ├── types.js │ │ │ ├── actions.js │ │ │ ├── index.js │ │ │ └── reducer.js │ │ └── store.js ├── utils │ ├── teleporter.js │ └── urlCreator.js ├── config.js.dist ├── hooks │ ├── useForceUpdate.js │ └── useCart.js ├── index.scss ├── index.js ├── logo.svg ├── serviceWorker.js └── edit.json ├── .env ├── public ├── favicon.ico ├── manifest.json └── index.html ├── .storybook ├── addons.js └── config.js ├── plop-templates └── Component.js.hbs ├── config-overrides.js ├── .vscode └── settings.json ├── stories ├── ProductAddToCart.stories.js └── ProductPrice.stories.js ├── codegen.yml ├── .gitignore ├── plopfile.js ├── tsconfig.json ├── package.json └── README.md /src/index.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | SASS_PATH=node_modules:src 2 | SKIP_PREFLIGHT_CHECK=true -------------------------------------------------------------------------------- /src/components/App/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component" -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/components/App/Content/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component" -------------------------------------------------------------------------------- /src/components/App/Footer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component" -------------------------------------------------------------------------------- /src/components/App/Theme/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component" -------------------------------------------------------------------------------- /src/components/Test/Debug/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; -------------------------------------------------------------------------------- /src/styles/_typography.scss: -------------------------------------------------------------------------------- 1 | pre { 2 | white-space: normal; 3 | } 4 | -------------------------------------------------------------------------------- /src/components/App/Navigation/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component" -------------------------------------------------------------------------------- /src/components/Pages/HomePage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; -------------------------------------------------------------------------------- /src/components/Utils/Loading/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; -------------------------------------------------------------------------------- /src/components/App/Content/component.css: -------------------------------------------------------------------------------- 1 | .Content { 2 | margin-top: 20px; 3 | } -------------------------------------------------------------------------------- /src/components/Atoms/Product/Price/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component" -------------------------------------------------------------------------------- /src/components/Molecules/ProductGrid/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component" -------------------------------------------------------------------------------- /src/components/Pages/CartPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./redux-container"; -------------------------------------------------------------------------------- /src/components/Pages/ErrorPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/Page/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./query-container"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/SearchPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /src/components/Atoms/Product/StockStatus/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component" -------------------------------------------------------------------------------- /src/components/Molecules/CustomerMenu/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; -------------------------------------------------------------------------------- /src/components/Molecules/ProductGrid/Item/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component" -------------------------------------------------------------------------------- /src/components/Pages/CartPage/Empty/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/CheckoutPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/CmsPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./query-container"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/DownloadsPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/LoginPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./redux-container"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/LogoutPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./redux-container"; -------------------------------------------------------------------------------- /src/components/Pages/NotFoundPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/WishlistPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /src/components/App/Navigation/Categories/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./query-container" -------------------------------------------------------------------------------- /src/components/Atoms/Product/AddToCart/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./redux-container" -------------------------------------------------------------------------------- /src/components/Molecules/CmsBlock/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./query-container"; 2 | -------------------------------------------------------------------------------- /src/components/Molecules/Messages/Item/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /src/components/Molecules/Messages/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./redux-container"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/CartPage/PriceBox/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/CategoryPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./query-container"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/CustomerPage/Address/View/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; -------------------------------------------------------------------------------- /src/components/Pages/CustomerPage/Address/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/CustomerPage/Dashboard/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; -------------------------------------------------------------------------------- /src/components/Pages/CustomerPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./redux-container"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/ProductPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./query-container"; 2 | -------------------------------------------------------------------------------- /src/state/graphql/mutations/createEmptyCart.graphql: -------------------------------------------------------------------------------- 1 | mutation { 2 | createEmptyCart 3 | } -------------------------------------------------------------------------------- /src/state/redux/ducks/common/initialState.js: -------------------------------------------------------------------------------- 1 | export default { 2 | locked: false 3 | }; 4 | -------------------------------------------------------------------------------- /src/state/redux/ducks/messages/initialState.js: -------------------------------------------------------------------------------- 1 | export default { 2 | items: [] 3 | }; 4 | -------------------------------------------------------------------------------- /src/components/App/Navigation/CustomerLogin/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./redux-container" -------------------------------------------------------------------------------- /src/components/App/Navigation/QuickSearch/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./redux-container"; -------------------------------------------------------------------------------- /src/components/Molecules/CustomerLoginForm/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./redux-container"; -------------------------------------------------------------------------------- /src/components/Pages/CustomerPage/Account/Edit/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/CustomerPage/Orders/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./query-container"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/CustomerPage/Orders/Order/index.jsx: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yireo-training/react-duka-playground/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/components/Pages/CustomerPage/Account/ChangePassword/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./component"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/CustomerPage/Account/Create/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./redux-container"; 2 | -------------------------------------------------------------------------------- /src/components/Pages/CustomerPage/Address/Edit/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./redux-container"; 2 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-actions/register'; 2 | import '@storybook/addon-links/register'; 3 | -------------------------------------------------------------------------------- /src/state/redux/ducks/cart/reducers/updateCart.js: -------------------------------------------------------------------------------- 1 | export default (state, action) => { 2 | return state; 3 | }; 4 | -------------------------------------------------------------------------------- /src/components/Test/Debug/component.css: -------------------------------------------------------------------------------- 1 | pre.Debug { 2 | white-space: pre-wrap; 3 | word-wrap: break-word; 4 | } 5 | -------------------------------------------------------------------------------- /src/state/redux/ducks/cart/initialState.js: -------------------------------------------------------------------------------- 1 | export default { 2 | id: "", 3 | items: [], 4 | locked: false 5 | }; 6 | -------------------------------------------------------------------------------- /src/state/redux/ducks/cart/reducers/updateProduct.js: -------------------------------------------------------------------------------- 1 | export default (state, action) => { 2 | return state; 3 | }; 4 | -------------------------------------------------------------------------------- /src/components/Pages/CustomerPage/component.css: -------------------------------------------------------------------------------- 1 | .CustomerPage { 2 | display: grid; 3 | grid-template-columns: 1fr 3fr; 4 | } 5 | -------------------------------------------------------------------------------- /src/state/redux/ducks/customer/initialState.js: -------------------------------------------------------------------------------- 1 | export default { 2 | token: "", 3 | data: { 4 | email: "" 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /src/state/redux/ducks/common/reducers/unlock.js: -------------------------------------------------------------------------------- 1 | export default state => { 2 | return Object.assign({}, state, { locked: false }); 3 | }; 4 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import { configure } from '@storybook/react'; 2 | 3 | configure(require.context('../stories', true, /\.stories\.js$/), module); 4 | -------------------------------------------------------------------------------- /src/state/graphql/queries/resolveCatalogUrlToId.graphql: -------------------------------------------------------------------------------- 1 | query resolve($url:String!) { 2 | urlResolver(url: $url) { 3 | id 4 | type 5 | } 6 | } -------------------------------------------------------------------------------- /src/state/redux/ducks/cart/reducers/setCartId.js: -------------------------------------------------------------------------------- 1 | export default (state, action) => { 2 | return Object.assign({}, state, { id: action.cartId }); 3 | }; 4 | -------------------------------------------------------------------------------- /src/state/redux/ducks/customer/reducers/setCustomerData.js: -------------------------------------------------------------------------------- 1 | export default (state, action) => { 2 | return Object.assign({}, state, { data: action.data }); 3 | }; 4 | -------------------------------------------------------------------------------- /src/components/App/Footer/component.css: -------------------------------------------------------------------------------- 1 | .Footer { 2 | margin-top: 40px; 3 | padding: 30px; 4 | border-top: 1px solid #ddd; 5 | background-color: #eee; 6 | } -------------------------------------------------------------------------------- /src/state/graphql/queries/cmsPage.graphql: -------------------------------------------------------------------------------- 1 | query cmsPage($id: Int) { 2 | cmsPage(id: $id) { 3 | content 4 | title 5 | content_heading 6 | } 7 | } -------------------------------------------------------------------------------- /src/styles/_product-grid.scss: -------------------------------------------------------------------------------- 1 | .products-grid, 2 | .products-list { 3 | > ol, 4 | > ul { 5 | list-style-type: none; 6 | padding: 0; 7 | } 8 | } -------------------------------------------------------------------------------- /src/state/redux/ducks/search/types.js: -------------------------------------------------------------------------------- 1 | // Action types 2 | const UPDATE_SEARCH = "apolloPlayground/search/UPDATE_SEARCH"; 3 | 4 | export default { 5 | UPDATE_SEARCH 6 | }; 7 | -------------------------------------------------------------------------------- /src/state/redux/ducks/customer/reducers/setCustomerToken.js: -------------------------------------------------------------------------------- 1 | export default (state, action) => { 2 | return Object.assign({}, state, { 3 | token: action.token 4 | }); 5 | }; 6 | -------------------------------------------------------------------------------- /src/utils/teleporter.js: -------------------------------------------------------------------------------- 1 | import { createTeleporter } from 'react-teleporter' 2 | 3 | const ContainerBelowContent = createTeleporter(); 4 | 5 | export { 6 | ContainerBelowContent 7 | } -------------------------------------------------------------------------------- /src/components/Pages/HomePage/component.css: -------------------------------------------------------------------------------- 1 | .HomePage .sidebar { 2 | border-left: 1px solid #ccc; 3 | padding: 10px; 4 | } 5 | 6 | .HomePage .sidebar img { 7 | max-width: 100%; 8 | } -------------------------------------------------------------------------------- /src/config.js.dist: -------------------------------------------------------------------------------- 1 | export default { 2 | magento_url: "https://duka.yireo-demo.com/", 3 | magento_url_suffix: ".html" 4 | //elasticsearch_url: "https://duka.yireo-demo.com/elasticsearch" 5 | }; -------------------------------------------------------------------------------- /src/components/Pages/CartPage/component.css: -------------------------------------------------------------------------------- 1 | .CartPage .totals tr td { 2 | text-align: right; 3 | } 4 | 5 | .CartPage .bottom { 6 | display: grid; 7 | grid-template-columns: 2fr 1fr; 8 | } -------------------------------------------------------------------------------- /src/utils/urlCreator.js: -------------------------------------------------------------------------------- 1 | import config from "config"; 2 | 3 | export default (url, prefix = "/") => { 4 | const suffix = config.magento_url_suffix; 5 | return `${prefix}${url}${suffix}`; 6 | }; 7 | -------------------------------------------------------------------------------- /src/state/redux/ducks/customer/reducers/postLogoutCustomer.js: -------------------------------------------------------------------------------- 1 | import initialState from "../initialState"; 2 | 3 | export default state => { 4 | return Object.assign({}, state, initialState); 5 | }; 6 | -------------------------------------------------------------------------------- /src/state/redux/ducks/cart/reducers/setCart.js: -------------------------------------------------------------------------------- 1 | export default (state, action) => { 2 | return Object.assign({}, state, { 3 | items: action.cart.items, 4 | prices: action.cart.prices 5 | }); 6 | }; 7 | -------------------------------------------------------------------------------- /src/state/graphql/mutations/generateCustomerToken.graphql: -------------------------------------------------------------------------------- 1 | mutation generateCustomerToken($email:String!, $password:String!) { 2 | generateCustomerToken(email:$email, password:$password) { 3 | token 4 | } 5 | } -------------------------------------------------------------------------------- /src/state/redux/ducks/common/types.js: -------------------------------------------------------------------------------- 1 | // Action types 2 | const LOCK = "apolloPlayground/common/LOCK"; 3 | const UNLOCK = "apolloPlayground/common/UNLOCK"; 4 | 5 | export default { 6 | LOCK, 7 | UNLOCK 8 | }; 9 | -------------------------------------------------------------------------------- /src/components/Pages/SearchPage/EmptySearchResults.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const EmptySearchResults = () => { 4 | return

No results were found

; 5 | }; 6 | 7 | export default EmptySearchResults; 8 | -------------------------------------------------------------------------------- /src/state/graphql/queries/customerOrders.graphql: -------------------------------------------------------------------------------- 1 | { 2 | customerOrders { 3 | items { 4 | created_at 5 | grand_total 6 | id 7 | increment_id 8 | status 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /src/state/graphql/queries/cmsBlock.graphql: -------------------------------------------------------------------------------- 1 | query cmsBlock($id:String) { 2 | cmsBlocks(identifiers: [ 3 | $id 4 | ]){ 5 | items { 6 | content 7 | identifier 8 | title 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /plop-templates/Component.js.hbs: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const {{pascalCase name}} = props => { 4 | return ( 5 |
6 | {{pascalCase name}} 7 |
8 | ); 9 | }; 10 | 11 | export default {{pascalCase name}}; -------------------------------------------------------------------------------- /src/components/Pages/CartPage/Empty/component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const CartPageEmpty = () => { 4 | return ( 5 |
The cart is empty
6 | ); 7 | }; 8 | 9 | export default CartPageEmpty; -------------------------------------------------------------------------------- /src/state/graphql/mutations/changeCustomerPassword.graphql: -------------------------------------------------------------------------------- 1 | mutation changeCustomerPassword($currentPassword: String!, $newPassword: String!) { 2 | changeCustomerPassword(currentPassword: $currentPassword, newPassword: $newPassword) { 3 | id 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/components/App/component.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './component'; 4 | it('renders without crashing', () => { 5 | const div = document.createElement('div'); 6 | ReactDOM.render(, div); 7 | }); 8 | -------------------------------------------------------------------------------- /src/hooks/useForceUpdate.js: -------------------------------------------------------------------------------- 1 | import { useState, useCallback } from "react"; 2 | 3 | export default () => { 4 | const [, setTick] = useState(0); 5 | const update = useCallback(() => { 6 | setTick(tick => tick + 1); 7 | }, []); 8 | return update; 9 | }; 10 | -------------------------------------------------------------------------------- /src/hooks/useCart.js: -------------------------------------------------------------------------------- 1 | import { useSelector } from "react-redux"; 2 | 3 | export default { 4 | useItemsCount: () => { 5 | const cartItems = useSelector(state => state.cart.items); 6 | return cartItems.reduce((total, item) => total + item.quantity, 0); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/state/graphql/queries/byAttribute.graphql-example: -------------------------------------------------------------------------------- 1 | query byAttibute($attribute_code: String) { 2 | productAttribute(code: $attribute_code) { 3 | code 4 | id 5 | options { 6 | label 7 | product_count 8 | value 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/state/graphql/queries/topLevelCategories.graphql: -------------------------------------------------------------------------------- 1 | query topLevelCategories { 2 | category(id: 2) { 3 | children { 4 | url_path 5 | id 6 | name 7 | children { 8 | url_path 9 | id 10 | name 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/state/graphql/mutations/removeCartItem.graphql: -------------------------------------------------------------------------------- 1 | mutation removeItemFromCart($cartId: String!, $id: Int!) { 2 | removeItemFromCart(input:{ 3 | cart_id: $cartId, 4 | cart_item_id: $id 5 | }) { 6 | cart { 7 | items { 8 | id 9 | } 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/state/redux/ducks/search/actions.js: -------------------------------------------------------------------------------- 1 | // Action Creators 2 | import types from "./types"; 3 | 4 | export const updateSearch = (search) => { 5 | return { 6 | type: types.UPDATE_SEARCH, 7 | search: search, 8 | }; 9 | }; 10 | 11 | export default { 12 | updateSearch, 13 | }; 14 | -------------------------------------------------------------------------------- /src/components/Test/Debug/component.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./component.css"; 3 | import JSONPretty from 'react-json-pretty'; 4 | 5 | const Debug = props => { 6 | return 7 | ; 8 | }; 9 | 10 | export default Debug; -------------------------------------------------------------------------------- /src/index.scss: -------------------------------------------------------------------------------- 1 | @import "styles/typography"; 2 | @import "styles/product-grid"; 3 | 4 | :root { 5 | --color-yireo: #c82529; 6 | --color-on-yireo: #fff; 7 | } 8 | 9 | img { 10 | max-width: 100%; 11 | height: auto; 12 | } 13 | 14 | :any-link { 15 | color: var(--color-yireo); 16 | } 17 | -------------------------------------------------------------------------------- /config-overrides.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const rewireGqlTag = require("react-app-rewire-graphql-tag"); 3 | 4 | module.exports = function override(config, env) { 5 | config.resolve.modules.unshift(path.resolve(__dirname, "src/lib")); 6 | config = rewireGqlTag(config, env); 7 | return config; 8 | }; 9 | -------------------------------------------------------------------------------- /src/components/Pages/WishlistPage/component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const WishlistPage = (props) => { 4 | return ( 5 |
6 |

Wishlist

7 |

Not implemented yet

8 |
9 | ); 10 | }; 11 | 12 | export default WishlistPage; 13 | -------------------------------------------------------------------------------- /src/components/Pages/DownloadsPage/component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const DownloadsPage = (props) => { 4 | return ( 5 |
6 |

Downloads

7 |

Not implemented yet

8 |
9 | ); 10 | }; 11 | 12 | export default DownloadsPage; 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "editor.acceptSuggestionOnCommitCharacter": false, 4 | "files.autoSave": "afterDelay", 5 | "files.autoSaveDelay": 5000, 6 | "editor.wordWrap": "on", 7 | "editor.formatOnSave": true, 8 | "editor.formatOnPaste": true, 9 | "editor.minimap.enabled": false 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Pages/CartPage/PriceBox/component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const PriceBox = (props) => { 4 | return ( 5 | 6 | {props.label} 7 | {props.price.currency} {props.price.value} 8 | 9 | ); 10 | } 11 | 12 | export default PriceBox; -------------------------------------------------------------------------------- /src/state/redux/ducks/common/reducers/lock.js: -------------------------------------------------------------------------------- 1 | export default (state, action) => { 2 | let callback = action.afterUnlockCallback 3 | ? action.afterUnlockCallback 4 | : state.afterUnlockCallback; 5 | 6 | return Object.assign({}, state, { 7 | locked: true, 8 | afterUnlockCallback: callback 9 | }); 10 | }; 11 | -------------------------------------------------------------------------------- /src/state/redux/ducks/search/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Search integrations with Redux following the ducks standard 3 | */ 4 | 5 | import searchReducer from "./reducer"; 6 | 7 | export { default as searchTypes } from "./types"; 8 | export { default as searchActions } from "./actions"; 9 | export default searchReducer; 10 | 11 | // End 12 | -------------------------------------------------------------------------------- /stories/ProductAddToCart.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AddToCart from "components/Atoms/Product/AddToCart/component"; 3 | 4 | export default { 5 | title: 'Product AddToCart' 6 | }; 7 | 8 | export const toStorybook = () => 9 | 10 | toStorybook.story = { 11 | name: 'Default content', 12 | }; 13 | -------------------------------------------------------------------------------- /src/components/App/Theme/component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { ContainerBelowContent } from "utils/teleporter" 3 | 4 | const Theme = () => { 5 | return ( 6 | <> 7 | Some copyright example 8 | 9 | ); 10 | } 11 | 12 | export default Theme; 13 | -------------------------------------------------------------------------------- /src/components/Utils/Loading/component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Spinner from 'react-bootstrap/Spinner' 3 | 4 | const Loading = () => { 5 | return ( 6 | 7 | Loading... 8 | 9 | ); 10 | }; 11 | 12 | export default Loading; 13 | -------------------------------------------------------------------------------- /src/state/graphql/mutations/updateCustomer.graphql: -------------------------------------------------------------------------------- 1 | mutation updateCustomer($email: String, $firstname: String, $lastname: String) { 2 | updateCustomer( 3 | input: { email: $email, firstname: $firstname, lastname: $lastname } 4 | ) { 5 | customer { 6 | email 7 | firstname 8 | lastname 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/state/redux/ducks/messages/types.js: -------------------------------------------------------------------------------- 1 | // Action types 2 | const ADD_MESSAGE = "apolloPlayground/messages/ADD_MESSAGE"; 3 | const REMOVE_MESSAGE = "apolloPlayground/messages/REMOVE_MESSAGE"; 4 | const CLEAN_MESSAGES = "apolloPlayground/messages/CLEAN_MESSAGES"; 5 | 6 | export default { 7 | ADD_MESSAGE, 8 | REMOVE_MESSAGE, 9 | CLEAN_MESSAGES 10 | }; 11 | -------------------------------------------------------------------------------- /src/state/redux/ducks/common/actions.js: -------------------------------------------------------------------------------- 1 | // Action Creators 2 | import types from "./types"; 3 | 4 | const lock = (afterUnlockCallback) => { 5 | return { type: types.LOCK, afterUnlockCallback: afterUnlockCallback }; 6 | }; 7 | 8 | const unlock = () => { 9 | return { type: types.UNLOCK }; 10 | }; 11 | 12 | export default { 13 | lock, 14 | unlock 15 | }; 16 | -------------------------------------------------------------------------------- /src/components/Pages/LogoutPage/component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Loading from "components/Utils/Loading"; 3 | import { Redirect } from "react-router-dom"; 4 | 5 | const LogoutPage = props => { 6 | if (!props.customerToken) { 7 | return ; 8 | } 9 | 10 | return ; 11 | }; 12 | 13 | export default LogoutPage; 14 | -------------------------------------------------------------------------------- /codegen.yml: -------------------------------------------------------------------------------- 1 | overwrite: true 2 | schema: "https://duka.yireo-demo.com/graphql" 3 | documents: "src/state/graphql/queries/*.graphql" 4 | generates: 5 | src/codegen/graphql.tsx: 6 | plugins: 7 | - "typescript" 8 | - "typescript-operations" 9 | - "typescript-react-apollo" 10 | src/codegen/graphql.schema.json: 11 | plugins: 12 | - "introspection" 13 | -------------------------------------------------------------------------------- /src/state/redux/ducks/cart/reducers/addProduct.js: -------------------------------------------------------------------------------- 1 | export default (state, action) => { 2 | /* 3 | let products = state.items ? state.items : []; 4 | let newProducts = [...products]; 5 | newProducts.push({ sku: action.sku, qty: action.qty }); 6 | let newState = Object.assign({}, state, { items: newProducts }); 7 | return newState; 8 | */ 9 | return state; 10 | }; 11 | -------------------------------------------------------------------------------- /src/state/redux/ducks/common/middleware/unlock.js: -------------------------------------------------------------------------------- 1 | const unlock = (store) => { 2 | const currentState = store.getState(); 3 | if (currentState.common.locked === true) { 4 | return; 5 | } 6 | 7 | if (currentState.common.afterUnlockCallback instanceof Function) { 8 | currentState.common.afterUnlockCallback.call(); 9 | } 10 | }; 11 | 12 | export default unlock; 13 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/components/Atoms/Product/StockStatus/component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const StockStatus = (props) => { 4 | const product = props.product; 5 | 6 | if (product.stock_status === undefined) { 7 | return <> 8 | } 9 | 10 | return ( 11 |
{product.stock_status}
12 | ) 13 | } 14 | 15 | export default StockStatus; -------------------------------------------------------------------------------- /src/state/graphql/queries/customProductAttribute.graphql: -------------------------------------------------------------------------------- 1 | query customProductAttribute($attribute_code: String) { 2 | customAttributeMetadata( 3 | attributes: { entity_type: "4", attribute_code: $attribute_code } 4 | ) { 5 | items { 6 | attribute_code 7 | attribute_options { 8 | label 9 | value 10 | } 11 | attribute_type 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/state/redux/ducks/messages/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Messages integrations with Redux following the ducks standard 3 | */ 4 | 5 | import messagesReducer from "./reducer"; 6 | 7 | export { default as messagesTypes } from "./types"; 8 | export { default as messagesActions } from "./actions"; 9 | export { default as messagesInitialState } from "./initialState"; 10 | export default messagesReducer; 11 | 12 | // End 13 | -------------------------------------------------------------------------------- /src/state/graphql/mutations/createCustomer.graphql: -------------------------------------------------------------------------------- 1 | mutation createCustomer($firstname: String, $lastname: String, $email: String, $password: String) { 2 | createCustomer( 3 | input: { 4 | firstname: $firstname 5 | lastname: $lastname 6 | email: $email 7 | password: $password 8 | } 9 | ) { 10 | customer { 11 | id 12 | firstname 13 | lastname 14 | email 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/components/Pages/NotFoundPage/component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const NotFoundPage = (props) => { 4 | return ( 5 |
6 |

404 - Page Not Found

7 |

Unfortunately, the page you were looking for could not be located.

8 | {props.reason && 9 |
{props.reason}
} 10 |
11 | ); 12 | }; 13 | 14 | export default NotFoundPage; 15 | -------------------------------------------------------------------------------- /src/state/redux/ducks/cart/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Cart integrations with Redux following the ducks standard 3 | */ 4 | 5 | import cartReducer from "./reducer"; 6 | export { default as cartTypes } from "./types"; 7 | export { default as cartMiddleware } from "./middleware"; 8 | export { default as cartActions } from "./actions"; 9 | export { default as cartInitialState } from "./initialState"; 10 | export default cartReducer; 11 | 12 | // End 13 | -------------------------------------------------------------------------------- /src/state/redux/ducks/cart/reducers/removeCartItem.js: -------------------------------------------------------------------------------- 1 | export default (state, action) => { 2 | return state; 3 | /* 4 | let products = state.items ? state.items : []; 5 | let newProducts = [...products]; 6 | 7 | newProducts.map((product, index) => { 8 | if (product.sku === action.sku) newProducts.splice(index, 1); 9 | return product; 10 | }); 11 | 12 | return Object.assign({}, state, { items: newProducts }); 13 | */ 14 | }; 15 | -------------------------------------------------------------------------------- /src/components/Pages/CustomerPage/Orders/Order/component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Order = (props) => { 4 | const order = props.order; 5 | return ( 6 | 7 | {order.id} 8 | {order.increment_id} 9 | {order.created_at} 10 | {order.grand_total} 11 | {order.status} 12 | 13 | ); 14 | }; 15 | 16 | export default Order; 17 | -------------------------------------------------------------------------------- /src/components/Pages/ErrorPage/component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ErrorPage = (props) => { 4 | let errorMessage = props.error; 5 | errorMessage = errorMessage.replace("GraphQL error: ", ""); 6 | 7 | return ( 8 |
9 |

Whoops, something went wrong

10 | {errorMessage && 11 |
{errorMessage}
} 12 |
13 | ); 14 | }; 15 | 16 | export default ErrorPage; 17 | -------------------------------------------------------------------------------- /src/state/redux/ducks/common/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Common integrations with Redux following the ducks standard 3 | */ 4 | 5 | import commonReducer from "./reducer"; 6 | export { default as commonTypes } from "./types"; 7 | export { default as commonMiddleware } from "./middleware"; 8 | export { default as commonActions } from "./actions"; 9 | export { default as commonInitialState } from "./initialState"; 10 | export default commonReducer; 11 | 12 | // End 13 | -------------------------------------------------------------------------------- /src/components/App/component.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Navigation from "components/App/Navigation"; 3 | import Content from "components/App/Content"; 4 | import Footer from "components/App/Footer"; 5 | import Theme from "components/App/Theme" 6 | 7 | const App = () => { 8 | return ( 9 | <> 10 | 11 | 12 | 13 |