From b6e9e5f2908b43d7e2596a4ac22976b2f178cf0f Mon Sep 17 00:00:00 2001 From: kube-js Date: Tue, 19 Nov 2019 20:47:42 +0000 Subject: [PATCH] fix: added checkout page --- k8s/Chart.yaml | 2 +- k8s/values.yaml | 2 +- src/app.tsx | 9 +- src/atoms/CartDropdown/styles.ts | 14 ++ src/components/CartCheckoutSidebar/index.tsx | 10 +- src/components/CartItems/index.tsx | 193 ++++++++++++++----- src/components/CartItems/styles.ts | 20 +- src/components/{Cart => CartView}/index.tsx | 35 +--- src/components/{Cart => CartView}/styles.ts | 0 src/components/CheckoutView/index.tsx | 62 ++++++ src/components/CheckoutView/styles.ts | 32 +++ src/constants/routes.ts | 3 +- src/i18n/translations/enGB/index.ts | 15 +- src/i18n/translations/plPL/index.ts | 26 +-- 14 files changed, 323 insertions(+), 100 deletions(-) create mode 100644 src/atoms/CartDropdown/styles.ts rename src/components/{Cart => CartView}/index.tsx (68%) rename src/components/{Cart => CartView}/styles.ts (100%) create mode 100644 src/components/CheckoutView/index.tsx create mode 100644 src/components/CheckoutView/styles.ts diff --git a/k8s/Chart.yaml b/k8s/Chart.yaml index 05d09381..cef5259e 100644 --- a/k8s/Chart.yaml +++ b/k8s/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v1 description: A Helm chart for kube-ts-react-client name: kube-ts-react-client version: 1.0.0 -appVersion: 1.6.14 +appVersion: 1.6.20 home: https://cloud.docker.com/u/kubejs/repository/docker/kubejs/kube-ts-react-client icon: https://avatars2.githubusercontent.com/u/47761918?s=200&v=4 sources: diff --git a/k8s/values.yaml b/k8s/values.yaml index 916060e5..2bd34a96 100644 --- a/k8s/values.yaml +++ b/k8s/values.yaml @@ -6,7 +6,7 @@ replicaCount: 2 image: repository: kubejs/kube-ts-react-client - tag: 1.6.14 + tag: 1.6.20 pullPolicy: Always containerPort: 80 diff --git a/src/app.tsx b/src/app.tsx index f6474250..034247da 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -3,14 +3,16 @@ import React, { Fragment, lazy, StrictMode, Suspense } from 'react'; import { Route, Switch } from 'react-router'; import AuthenticatedRoute from './components/Auth/AuthenticatedRoute'; import UnauthenticatedRoute from './components/Auth/UnauthenticatedRoute'; -import CartView from './components/Cart'; +import CartView from './components/CartView'; +import CheckoutView from './components/CheckoutView'; import CourseView from './components/CourseView'; import ErrorBoundary from './components/ErrorBoundaries/Page/index'; import InstructorView from './components/InstructorView'; import Layout from './components/Layout'; import { CART, - COURSE_VIEW, + CHECKOUT, + COURSE, DASHBOARD, INSTRUCTOR_VIEW, LOGIN, @@ -42,7 +44,7 @@ const App = () => ( - + @@ -66,6 +68,7 @@ const App = () => ( /> + diff --git a/src/atoms/CartDropdown/styles.ts b/src/atoms/CartDropdown/styles.ts new file mode 100644 index 00000000..ab378177 --- /dev/null +++ b/src/atoms/CartDropdown/styles.ts @@ -0,0 +1,14 @@ +// tslint:disable:no-magic-numbers +import { makeStyles } from '@material-ui/core/styles'; + +const useStyles = makeStyles(() => ({ + dropdown: { + '&:hover': { + background: 'red', + }, + alignItems: 'center', + display: 'flex', + }, +})); + +export default useStyles; diff --git a/src/components/CartCheckoutSidebar/index.tsx b/src/components/CartCheckoutSidebar/index.tsx index dcfc804b..7917ce6f 100644 --- a/src/components/CartCheckoutSidebar/index.tsx +++ b/src/components/CartCheckoutSidebar/index.tsx @@ -4,22 +4,30 @@ import Paper from '@material-ui/core/Paper'; import _isNil from 'ramda/src/isNil'; import React from 'react'; import { useTranslation } from 'react-i18next'; +import { useHistory } from 'react-router'; +import { CHECKOUT } from '../../constants/routes'; import sumBy from '../../utils/helpers/sumBy'; import useStyles from './styles'; const CartItems = ({ items }: any) => { const classes = useStyles(); const { t } = useTranslation(); + const history = useHistory(); const courses = items.length === 1 ? t('cart.item') : t('cart.items'); const total = sumBy('price')(items); + const goTo = (url: string) => (e: any) => { + e.preventDefault(); + history.push(url); + }; + return ( {t('cart.total')} ({items.length} {courses}): £{total.toFixed(2)} - diff --git a/src/components/CartItems/index.tsx b/src/components/CartItems/index.tsx index 1073621e..5a05adf8 100644 --- a/src/components/CartItems/index.tsx +++ b/src/components/CartItems/index.tsx @@ -6,78 +6,175 @@ import TableCell from '@material-ui/core/TableCell'; import TableHead from '@material-ui/core/TableHead'; // tslint:disable:no-magic-numbers import TableRow from '@material-ui/core/TableRow'; +import CheckIcon from '@material-ui/icons/Check'; import DeleteIcon from '@material-ui/icons/Delete'; +import EditIcon from '@material-ui/icons/Edit'; +import ShoppingCartIcon from '@material-ui/icons/ShoppingCart'; import _isNil from 'ramda/src/isNil'; -import React from 'react'; +import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useHistory } from 'react-router'; +import { useHistory, useLocation } from 'react-router'; import courseImagePlaceholder from '../../images/course_400x180.png'; +import { EnhancedCourse } from '../../redux/discoveryItems/actionCreators'; import assetsUrl from '../../utils/helpers/assetsUrl'; import sumBy from '../../utils/helpers/sumBy'; import useStyles from './styles'; -const CartItems = ({ items, removeItem }: any) => { +export interface Options { + readonly items: EnhancedCourse[]; + readonly removeItem: (id: string) => (e: any) => void; +} + +const CartItems = ({ items, removeItem }: Options) => { const classes = useStyles(); const history = useHistory(); const { t } = useTranslation(); - const goTo = (slug: string) => (e: any) => { + const goTo = (url: string) => (e: any) => { e.preventDefault(); - history.push(`/courses/${slug}`); + history.push(url); }; const courses = items.length === 1 ? t('cart.item') : t('cart.items'); const total = sumBy('price')(items); + const { search } = useLocation(); + + const params = new URLSearchParams(search); + + const newItemId = params.get('newItemId'); + + const initialState = !newItemId; + + const [isEditable, setIsEditable] = useState(initialState); + + const enableEditing = (e: any) => { + e.preventDefault(); + + return setIsEditable(true); + }; + + const addedItem = items.find(item => item.id === newItemId); + let addedItemImageUrl; + + if (addedItem !== undefined) { + addedItemImageUrl = + addedItem !== undefined && _isNil(addedItem.imageUrl) + ? courseImagePlaceholder + : assetsUrl(addedItem.imageUrl); + } + return ( - - - - {t('cart.price')} - - - - {items.map((item: any) => { - const imageUrl = _isNil(item.imageUrl) - ? courseImagePlaceholder - : assetsUrl(item.imageUrl); - - return ( - - - {item.title} - - - - {item.title} - - - - {item.price} - - ); - })} - - - - {t('cart.total')} ({items.length} {courses}): £{total} - - - + {isEditable || addedItem === undefined ? ( + <> + {items.length > 0 ? ( + + + + {t('cart.price')} + + + ) : null} + + {items.map((item: any) => { + const imageUrl = _isNil(item.imageUrl) + ? courseImagePlaceholder + : assetsUrl(item.imageUrl); + + return ( + + + {item.title} + + + + {item.title} + +

+ {t('cart.instructor')}: {item.user.firstName}{' '} + {item.user.lastName} +

+
+ + + + {item.price} +
+ ); + })} + {items.length > 0 ? ( + + + + {t('cart.total')} ({items.length} {courses}): £{total} + + + ) : null} + + {items.length === 0 ? ( + + + + {t('cart.yourCartIsEmpty')} + + + + + ) : null} +
+ + ) : null} + {!isEditable && addedItem !== undefined ? ( + + + +
+
+ {addedItem.title} +
+
+ + {t('cart.addedToCart')} +
+
+
+ + + {addedItem.title} + + + + + + + {t('cart.total')} ({items.length} {courses}): £{total} + +
+
+ ) : null}
); }; +// tslint:disable-next-line:max-file-line-count export default CartItems; diff --git a/src/components/CartItems/styles.ts b/src/components/CartItems/styles.ts index ab5fe184..43392201 100644 --- a/src/components/CartItems/styles.ts +++ b/src/components/CartItems/styles.ts @@ -2,9 +2,25 @@ import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; const useStyles = makeStyles((theme: Theme) => createStyles({ + addedToBasket: { + display: 'flex', + flexDirection: 'column', + }, + addedToBasketContent: { + '& svg': { + color: 'green', + }, + alignItems: 'center', + display: 'flex', + }, + addedToBasketImageWrapper: { + '&img': { + minWidth: 150, + }, + }, itemImage: { - height: 60, - width: 100, + height: 100, + width: 150, }, root: { border: '1px solid rgba(0, 0, 0, .125)', diff --git a/src/components/Cart/index.tsx b/src/components/CartView/index.tsx similarity index 68% rename from src/components/Cart/index.tsx rename to src/components/CartView/index.tsx index 36b251b7..78c5ee66 100644 --- a/src/components/Cart/index.tsx +++ b/src/components/CartView/index.tsx @@ -1,10 +1,9 @@ // tslint:disable:no-magic-numbers import { Container, Grid, Typography } from '@material-ui/core'; import _isNil from 'ramda/src/isNil'; -import React, { memo, useState } from 'react'; +import React, { memo } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; -import { useLocation } from 'react-router'; import { removeCartItem } from '../../redux/cart/actionCreators'; import { State } from '../../redux/rootReducer'; import CartCheckoutSidebar from '../CartCheckoutSidebar'; @@ -15,22 +14,6 @@ const CartView = () => { const classes = useStyles(); const { t } = useTranslation(); - const { search } = useLocation(); - - const params = new URLSearchParams(search); - - const newItemId = params.get('newItemId'); - - const initialState = !newItemId; - - const [editMode, setEditMode] = useState(initialState); - - const toggleEditMode = (e: any) => { - e.preventDefault(); - - return setEditMode(!editMode); - }; - const { items } = useSelector((state: State) => state.cart); const dispatch = useDispatch(); @@ -61,15 +44,13 @@ const CartView = () => { - {editMode ? ( - <> - - - - - - - + 0 ? 9 : 12}> + + + {items.length > 0 ? ( + + + ) : null} diff --git a/src/components/Cart/styles.ts b/src/components/CartView/styles.ts similarity index 100% rename from src/components/Cart/styles.ts rename to src/components/CartView/styles.ts diff --git a/src/components/CheckoutView/index.tsx b/src/components/CheckoutView/index.tsx new file mode 100644 index 00000000..74c88f49 --- /dev/null +++ b/src/components/CheckoutView/index.tsx @@ -0,0 +1,62 @@ +// tslint:disable:no-magic-numbers +import { Container, Grid, Typography } from '@material-ui/core'; +import _isNil from 'ramda/src/isNil'; +import React, { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useDispatch, useSelector } from 'react-redux'; +// import { removeCartItem } from '../../redux/cart/actionCreators'; +import { State } from '../../redux/rootReducer'; +// import CartCheckoutSidebar from '../CartCheckoutSidebar'; +// import CartItems from '../CartItems'; +import useStyles from './styles'; + +const CheckoutView = () => { + const classes = useStyles(); + const { t } = useTranslation(); + + const { items } = useSelector((state: State) => state.cart); + + const dispatch = useDispatch(); + + // const courseItems = items.map(item => ({ ...item, price: 19.99 })); + + // const removeItem = (id: string) => (e: any) => { + // e.preventDefault(); + // dispatch(removeCartItem(id)); + // }; + + return ( +
+ + + + + + Checkout + + + + + + {/* + + 0 ? 9 : 12}> + + + {items.length > 0 ? ( + + + + ) : null} + + */} +
+ ); +}; + +// tslint:disable-next-line:max-file-line-count +export default memo(CheckoutView); diff --git a/src/components/CheckoutView/styles.ts b/src/components/CheckoutView/styles.ts new file mode 100644 index 00000000..975f8cef --- /dev/null +++ b/src/components/CheckoutView/styles.ts @@ -0,0 +1,32 @@ +// tslint:disable:no-magic-numbers +import { makeStyles } from '@material-ui/core/styles'; + +const useStyles = makeStyles(theme => ({ + avatar: { + backgroundColor: 'orange', + color: '#fff', + margin: 10, + }, + contentHeadline: { + fontSize: '1.5rem', + lineHeight: '2rem', + margin: '1rem 0', + }, + mainHeadline: { + color: '#fff', + fontSize: '1.8rem', + fontWeight: 'bold', + marginBottom: '1rem', + marginTop: '1rem', + }, + root: { + flexGrow: 1, + }, + topSection: { + backgroundColor: '#24292e', + padding: '40px 0', + width: '100%', + }, +})); + +export default useStyles; diff --git a/src/constants/routes.ts b/src/constants/routes.ts index 2ed5d05b..7e88dfe0 100644 --- a/src/constants/routes.ts +++ b/src/constants/routes.ts @@ -5,6 +5,7 @@ export const RESET_PASSWORD = '/reset-password'; export const VERIFY = '/verify'; export const LOGIN = '/login'; export const DASHBOARD = '/dashboard'; -export const COURSE_VIEW = '/courses/:courseSlug'; +export const COURSE = '/courses/:courseSlug'; export const INSTRUCTOR_VIEW = '/instructors/:username'; export const CART = '/cart'; +export const CHECKOUT = '/checkout'; diff --git a/src/i18n/translations/enGB/index.ts b/src/i18n/translations/enGB/index.ts index 02e07c4f..eb377951 100644 --- a/src/i18n/translations/enGB/index.ts +++ b/src/i18n/translations/enGB/index.ts @@ -1,6 +1,7 @@ export default { auth: { - accountHasBeenVerified: 'Account has been verified successfuly. You can now', + accountHasBeenVerified: + 'Account has been verified successfuly. You can now', alreadyHaveAccount: 'Already have an account? Log in', backToLogin: 'Back to login', dontHaveAccount: "Don't have an account? Register", @@ -12,7 +13,8 @@ export default { newPasswordConfirmation: 'New password confirmation', password: 'Password', passwordConfirmation: 'Password confirmation', - passwordHelperText: 'Password must be 8 characters long, containing at least: 1 upper and 1 lower case, 1 digit and 1 special characters i.e. one of the following: #?!@$%^&*-', + passwordHelperText: + 'Password must be 8 characters long, containing at least: 1 upper and 1 lower case, 1 digit and 1 special characters i.e. one of the following: #?!@$%^&*-', register: 'Registration', registerAction: 'Register', remindPassword: 'Remind Password', @@ -23,23 +25,26 @@ export default { addToCart: 'Add to cart', addedToCart: 'Added to cart', buyNow: 'Buy now', + editCart: 'Edit cart', goToCart: 'Go to cart', instructor: 'Instructor', item: 'course', items: 'courses', + keepShopping: 'Keep shopping', mainHeadline: 'Shopping cart', price: 'Price', proceedToCheckout: 'Proceed to checkout', total: 'Total', + yourCartIsEmpty: 'Your cart is empty', }, courseView: { instructor: 'Instructor', - learningContent: 'Learning content:' + learningContent: 'Learning content:', }, dashboard: { accountHasBeenVerified: 'Account has not been verified yet. Click', mainHeader: 'Dashboard', - toVerifyYourAccount: 'to verify your account.' + toVerifyYourAccount: 'to verify your account.', }, global: { here: 'here', @@ -56,7 +61,7 @@ export default { }, home: { exploreOurBestsellers: 'Explore our bestsellers', - studentAreViewing: 'Student are viewing' + studentAreViewing: 'Student are viewing', }, navbar: { login: 'Login', diff --git a/src/i18n/translations/plPL/index.ts b/src/i18n/translations/plPL/index.ts index 44d75168..b4345558 100644 --- a/src/i18n/translations/plPL/index.ts +++ b/src/i18n/translations/plPL/index.ts @@ -1,9 +1,10 @@ export default { auth: { - accountHasBeenVerified: 'Konto zostało zweryfikowane pomyślnie. Teraz możesz', + accountHasBeenVerified: + 'Konto zostało zweryfikowane pomyślnie. Teraz możesz', alreadyHaveAccount: 'Masz już konto? Zaloguj się', - backToLogin: 'Wróć to logowania', - dontHaveAccount: "Nie masz jeszcze konta? Zarejestruj się", + backToLogin: 'Wróć to logowania', + dontHaveAccount: 'Nie masz jeszcze konta? Zarejestruj się', email: 'Adres e-mail', forgotPassword: 'Zapomniałeś hasła?', login: 'Logowanie', @@ -12,7 +13,8 @@ export default { newPasswordConfirmation: 'Potwierdzenie nowego hasła', password: 'Hasło', passwordConfirmation: 'Potwierdź hasło', - passwordHelperText: 'Hasło musi mieć minimum 8 znaków, zawierający co najmniej: jedną dużą i jedną małą literę jedną cyfrę i jeden znak specjalny (np. jeden z następujących: #?!@$%^&*-)', + passwordHelperText: + 'Hasło musi mieć minimum 8 znaków, zawierający co najmniej: jedną dużą i jedną małą literę jedną cyfrę i jeden znak specjalny (np. jeden z następujących: #?!@$%^&*-)', register: 'Rejestracja', registerAction: 'Zarejestruj', remindPassword: 'Przypomnij hasło', @@ -23,41 +25,43 @@ export default { addToCart: 'Dodaj do koszyka', addedToCart: 'Dodano do koszyka', buyNow: 'Kup teraz', + editCart: 'Edytuj koszyk', goToCart: 'Przejdź do koszyka', instructor: 'Instruktor', item: 'kurs', items: 'kursy', + keepShopping: 'Kontynuuj zakupy', mainHeadline: 'Koszyk', price: 'Cena', proceedToCheckout: 'Przejdź do kasy', total: 'Suma', + yourCartIsEmpty: 'Your cart is empty', }, courseView: { instructor: 'Instruktor', - learningContent: 'Treść kursu:' + learningContent: 'Treść kursu:', }, dashboard: { accountHasBeenVerified: 'Konto nie zostało jeszcze zweryfikowane. Kliknij', mainHeader: 'Panel roboczy', - toVerifyYourAccount: 'aby zweryfikować swoje konto.' + toVerifyYourAccount: 'aby zweryfikować swoje konto.', }, global: { here: 'tutaj', loading: 'ładowanie...', refreshThePage: ' Odśwież stronę', - somethingWentWrong: 'Coś poszło nie tak...' - + somethingWentWrong: 'Coś poszło nie tak...', }, heroContent: { mainHeading: 'Ucz się bez limitów', search: { - placeholder: 'Czego chciałbyś się dziś nauczyć?' + placeholder: 'Czego chciałbyś się dziś nauczyć?', }, subHeading: 'Znajdź kurs i zacznij naukę już teraz!', }, home: { exploreOurBestsellers: 'Zobacz nasze bestsellery', - studentAreViewing: 'Popularne wśród innych' + studentAreViewing: 'Popularne wśród innych', }, navbar: { login: 'Zaloguj się', @@ -67,4 +71,4 @@ export default { placeholder: 'Szukaj', }, }, -} \ No newline at end of file +};