Skip to content

Commit 1459197

Browse files
authored
Merge pull request #118 from kube-js/develop
fix: added checkout page
2 parents 2ebf766 + b6e9e5f commit 1459197

File tree

14 files changed

+323
-100
lines changed

14 files changed

+323
-100
lines changed

k8s/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ apiVersion: v1
22
description: A Helm chart for kube-ts-react-client
33
name: kube-ts-react-client
44
version: 1.0.0
5-
appVersion: 1.6.14
5+
appVersion: 1.6.20
66
home: https://cloud.docker.com/u/kubejs/repository/docker/kubejs/kube-ts-react-client
77
icon: https://avatars2.githubusercontent.com/u/47761918?s=200&v=4
88
sources:

k8s/values.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ replicaCount: 2
66

77
image:
88
repository: kubejs/kube-ts-react-client
9-
tag: 1.6.14
9+
tag: 1.6.20
1010
pullPolicy: Always
1111
containerPort: 80
1212

src/app.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ import React, { Fragment, lazy, StrictMode, Suspense } from 'react';
33
import { Route, Switch } from 'react-router';
44
import AuthenticatedRoute from './components/Auth/AuthenticatedRoute';
55
import UnauthenticatedRoute from './components/Auth/UnauthenticatedRoute';
6-
import CartView from './components/Cart';
6+
import CartView from './components/CartView';
7+
import CheckoutView from './components/CheckoutView';
78
import CourseView from './components/CourseView';
89
import ErrorBoundary from './components/ErrorBoundaries/Page/index';
910
import InstructorView from './components/InstructorView';
1011
import Layout from './components/Layout';
1112
import {
1213
CART,
13-
COURSE_VIEW,
14+
CHECKOUT,
15+
COURSE,
1416
DASHBOARD,
1517
INSTRUCTOR_VIEW,
1618
LOGIN,
@@ -42,7 +44,7 @@ const App = () => (
4244
<ErrorBoundary>
4345
<Switch>
4446
<Route exact path={ROOT} component={Home} />
45-
<Route exact path={COURSE_VIEW} component={CourseView} />
47+
<Route exact path={COURSE} component={CourseView} />
4648
<Route exact path={RESET_PASSWORD} component={ResetPassword} />
4749
<Route exact path={VERIFY} component={VerifyAccount} />
4850
<Route path={INSTRUCTOR_VIEW} component={InstructorView} />
@@ -66,6 +68,7 @@ const App = () => (
6668
/>
6769

6870
<Route exact path={CART} component={CartView} />
71+
<Route exact path={CHECKOUT} component={CheckoutView} />
6972

7073
<Route component={NotFound} />
7174
</Switch>

src/atoms/CartDropdown/styles.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// tslint:disable:no-magic-numbers
2+
import { makeStyles } from '@material-ui/core/styles';
3+
4+
const useStyles = makeStyles(() => ({
5+
dropdown: {
6+
'&:hover': {
7+
background: 'red',
8+
},
9+
alignItems: 'center',
10+
display: 'flex',
11+
},
12+
}));
13+
14+
export default useStyles;

src/components/CartCheckoutSidebar/index.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,30 @@ import Paper from '@material-ui/core/Paper';
44
import _isNil from 'ramda/src/isNil';
55
import React from 'react';
66
import { useTranslation } from 'react-i18next';
7+
import { useHistory } from 'react-router';
8+
import { CHECKOUT } from '../../constants/routes';
79
import sumBy from '../../utils/helpers/sumBy';
810
import useStyles from './styles';
911

1012
const CartItems = ({ items }: any) => {
1113
const classes = useStyles();
1214
const { t } = useTranslation();
15+
const history = useHistory();
1316
const courses = items.length === 1 ? t('cart.item') : t('cart.items');
1417
const total = sumBy('price')(items);
1518

19+
const goTo = (url: string) => (e: any) => {
20+
e.preventDefault();
21+
history.push(url);
22+
};
23+
1624
return (
1725
<Paper className={classes.paper} square>
1826
<Typography>
1927
{t('cart.total')} ({items.length} {courses}): £{total.toFixed(2)}
2028
</Typography>
2129

22-
<Button variant="contained" fullWidth color="secondary">
30+
<Button variant="contained" fullWidth color="secondary" onClick={goTo(CHECKOUT)}>
2331
{t('cart.proceedToCheckout')}
2432
</Button>
2533
</Paper>

src/components/CartItems/index.tsx

Lines changed: 145 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,78 +6,175 @@ import TableCell from '@material-ui/core/TableCell';
66
import TableHead from '@material-ui/core/TableHead';
77
// tslint:disable:no-magic-numbers
88
import TableRow from '@material-ui/core/TableRow';
9+
import CheckIcon from '@material-ui/icons/Check';
910
import DeleteIcon from '@material-ui/icons/Delete';
11+
import EditIcon from '@material-ui/icons/Edit';
12+
import ShoppingCartIcon from '@material-ui/icons/ShoppingCart';
1013
import _isNil from 'ramda/src/isNil';
11-
import React from 'react';
14+
import React, { useState } from 'react';
1215
import { useTranslation } from 'react-i18next';
13-
import { useHistory } from 'react-router';
16+
import { useHistory, useLocation } from 'react-router';
1417
import courseImagePlaceholder from '../../images/course_400x180.png';
18+
import { EnhancedCourse } from '../../redux/discoveryItems/actionCreators';
1519
import assetsUrl from '../../utils/helpers/assetsUrl';
1620
import sumBy from '../../utils/helpers/sumBy';
1721
import useStyles from './styles';
1822

19-
const CartItems = ({ items, removeItem }: any) => {
23+
export interface Options {
24+
readonly items: EnhancedCourse[];
25+
readonly removeItem: (id: string) => (e: any) => void;
26+
}
27+
28+
const CartItems = ({ items, removeItem }: Options) => {
2029
const classes = useStyles();
2130
const history = useHistory();
2231
const { t } = useTranslation();
2332

24-
const goTo = (slug: string) => (e: any) => {
33+
const goTo = (url: string) => (e: any) => {
2534
e.preventDefault();
26-
history.push(`/courses/${slug}`);
35+
history.push(url);
2736
};
2837

2938
const courses = items.length === 1 ? t('cart.item') : t('cart.items');
3039
const total = sumBy('price')(items);
3140

41+
const { search } = useLocation();
42+
43+
const params = new URLSearchParams(search);
44+
45+
const newItemId = params.get('newItemId');
46+
47+
const initialState = !newItemId;
48+
49+
const [isEditable, setIsEditable] = useState(initialState);
50+
51+
const enableEditing = (e: any) => {
52+
e.preventDefault();
53+
54+
return setIsEditable(true);
55+
};
56+
57+
const addedItem = items.find(item => item.id === newItemId);
58+
let addedItemImageUrl;
59+
60+
if (addedItem !== undefined) {
61+
addedItemImageUrl =
62+
addedItem !== undefined && _isNil(addedItem.imageUrl)
63+
? courseImagePlaceholder
64+
: assetsUrl(addedItem.imageUrl);
65+
}
66+
3267
return (
3368
<Paper className={classes.root} square>
3469
<Table className={classes.table} aria-label="table">
35-
<TableHead>
36-
<TableRow>
37-
<TableCell colSpan={3}></TableCell>
38-
<TableCell align="right">{t('cart.price')}</TableCell>
39-
</TableRow>
40-
</TableHead>
41-
<TableBody>
42-
{items.map((item: any) => {
43-
const imageUrl = _isNil(item.imageUrl)
44-
? courseImagePlaceholder
45-
: assetsUrl(item.imageUrl);
46-
47-
return (
48-
<TableRow key={item.title}>
49-
<TableCell>
50-
<img
51-
alt={item.title}
52-
src={imageUrl}
53-
className={classes.itemImage}
54-
/>
55-
</TableCell>
56-
<TableCell colSpan={2}>
57-
<a
58-
onClick={goTo(item.slug)}
59-
style={{ cursor: 'pointer' }}
60-
>
61-
{item.title}
62-
</a>
63-
<Button size="small" onClick={removeItem(item.id)}>
64-
<DeleteIcon />
65-
</Button>
66-
</TableCell>
67-
<TableCell align="right">{item.price}</TableCell>
68-
</TableRow>
69-
);
70-
})}
71-
<TableRow>
72-
<TableCell colSpan={3} />
73-
<TableCell align="right">
74-
{t('cart.total')} ({items.length} {courses}): £{total}
75-
</TableCell>
76-
</TableRow>
77-
</TableBody>
70+
{isEditable || addedItem === undefined ? (
71+
<>
72+
{items.length > 0 ? (
73+
<TableHead>
74+
<TableRow>
75+
<TableCell colSpan={3}></TableCell>
76+
<TableCell align="right">{t('cart.price')}</TableCell>
77+
</TableRow>
78+
</TableHead>
79+
) : null}
80+
<TableBody>
81+
{items.map((item: any) => {
82+
const imageUrl = _isNil(item.imageUrl)
83+
? courseImagePlaceholder
84+
: assetsUrl(item.imageUrl);
85+
86+
return (
87+
<TableRow key={item.title}>
88+
<TableCell>
89+
<img
90+
alt={item.title}
91+
src={imageUrl}
92+
className={classes.itemImage}
93+
/>
94+
</TableCell>
95+
<TableCell>
96+
<a
97+
onClick={goTo(`/courses/${item.slug}`)}
98+
style={{ cursor: 'pointer' }}
99+
>
100+
<Typography variant="subtitle1">{item.title}</Typography>
101+
</a>
102+
<p>
103+
{t('cart.instructor')}: {item.user.firstName}{' '}
104+
{item.user.lastName}
105+
</p>
106+
</TableCell>
107+
<TableCell>
108+
<Button size="small" onClick={removeItem(item.id)}>
109+
<DeleteIcon />
110+
</Button>
111+
</TableCell>
112+
<TableCell align="right">{item.price}</TableCell>
113+
</TableRow>
114+
);
115+
})}
116+
{items.length > 0 ? (
117+
<TableRow>
118+
<TableCell colSpan={3} />
119+
<TableCell align="right">
120+
{t('cart.total')} ({items.length} {courses}): £{total}
121+
</TableCell>
122+
</TableRow>
123+
) : null}
124+
125+
{items.length === 0 ? (
126+
<TableRow>
127+
<TableCell>
128+
<Typography variant="h6">
129+
{t('cart.yourCartIsEmpty')}
130+
</Typography>
131+
<Button size="small" onClick={goTo('/')}>
132+
<ShoppingCartIcon /> {t('cart.keepShopping')}
133+
</Button>
134+
</TableCell>
135+
</TableRow>
136+
) : null}
137+
</TableBody>
138+
</>
139+
) : null}
140+
{!isEditable && addedItem !== undefined ? (
141+
<TableBody>
142+
<TableRow>
143+
<TableCell>
144+
<div className={classes.addedToBasket}>
145+
<div className={classes.addedToBasketImageWrapper}>
146+
<img
147+
alt={addedItem.title}
148+
src={addedItemImageUrl}
149+
className={classes.itemImage}
150+
/>
151+
</div>
152+
<div className={classes.addedToBasketContent}>
153+
<CheckIcon />
154+
<Typography>{t('cart.addedToCart')}</Typography>
155+
</div>
156+
</div>
157+
</TableCell>
158+
<TableCell colSpan={2}>
159+
<a onClick={goTo(addedItem.slug)} style={{ cursor: 'pointer' }}>
160+
{addedItem.title}
161+
</a>
162+
</TableCell>
163+
<TableCell align="right">
164+
<Button size="small" onClick={enableEditing}>
165+
<EditIcon /> {t('cart.editCart')}
166+
</Button>
167+
</TableCell>
168+
<TableCell align="right">
169+
{t('cart.total')} ({items.length} {courses}): £{total}
170+
</TableCell>
171+
</TableRow>
172+
</TableBody>
173+
) : null}
78174
</Table>
79175
</Paper>
80176
);
81177
};
82178

179+
// tslint:disable-next-line:max-file-line-count
83180
export default CartItems;

src/components/CartItems/styles.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,25 @@ import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
22

33
const useStyles = makeStyles((theme: Theme) =>
44
createStyles({
5+
addedToBasket: {
6+
display: 'flex',
7+
flexDirection: 'column',
8+
},
9+
addedToBasketContent: {
10+
'& svg': {
11+
color: 'green',
12+
},
13+
alignItems: 'center',
14+
display: 'flex',
15+
},
16+
addedToBasketImageWrapper: {
17+
'&img': {
18+
minWidth: 150,
19+
},
20+
},
521
itemImage: {
6-
height: 60,
7-
width: 100,
22+
height: 100,
23+
width: 150,
824
},
925
root: {
1026
border: '1px solid rgba(0, 0, 0, .125)',

0 commit comments

Comments
 (0)