Skip to content

Commit 467d328

Browse files
committed
Checkout flow done
1 parent e8cbde0 commit 467d328

File tree

8 files changed

+570
-39
lines changed

8 files changed

+570
-39
lines changed

src/App.js

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import AuthProvider from "contexts/auth";
44
import CommonProvider from "contexts/common";
55
import ProductsProvider from "contexts/products";
66
import CartProvider from "contexts/cart";
7+
import CheckoutProvider from "contexts/checkout";
78
import RouteWrapper from "layouts/RouteWrapper";
89
import AuthLayout from "layouts/AuthLayout";
910
import CommonLayout from "layouts/CommonLayout";
@@ -18,27 +19,28 @@ const App = () => {
1819
<CommonProvider>
1920
<ProductsProvider>
2021
<CartProvider>
21-
<Router>
22-
<Switch>
23-
<RouteWrapper
24-
path="/"
25-
exact
26-
component={HomePage}
27-
layout={CommonLayout}
28-
/>
29-
<RouteWrapper
30-
path="/checkout"
31-
component={CheckoutPage}
32-
layout={CommonLayout}
33-
isPrivate
34-
/>
35-
<RouteWrapper
36-
path="/auth"
37-
component={AuthPage}
38-
layout={AuthLayout}
39-
/>
40-
</Switch>
41-
</Router>
22+
<CheckoutProvider>
23+
<Router>
24+
<Switch>
25+
<RouteWrapper
26+
path="/"
27+
exact
28+
component={HomePage}
29+
layout={CommonLayout}
30+
/>
31+
<RouteWrapper
32+
path="/checkout"
33+
component={CheckoutPage}
34+
layout={CommonLayout}
35+
/>
36+
<RouteWrapper
37+
path="/auth"
38+
component={AuthPage}
39+
layout={AuthLayout}
40+
/>
41+
</Switch>
42+
</Router>
43+
</CheckoutProvider>
4244
</CartProvider>
4345
</ProductsProvider>
4446
</CommonProvider>

src/assets/scss/base/_icons.scss

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
@font-face {
2+
font-family: "rsc";
3+
src: url("../../fonts/rsc/fonts/rsc.ttf?fxihkr") format("truetype"),
4+
url("../../fonts/rsc/fonts/rsc.woff?fxihkr") format("woff"),
5+
url("../../fonts/rsc/fonts/rsc.svg?fxihkr#rsc") format("svg");
6+
font-weight: normal;
7+
font-style: normal;
8+
font-display: block;
9+
}
10+
11+
[class^="rsc-icon-"],
12+
[class*=" rsc-icon-"] {
13+
/* use !important to prevent issues with browser extensions that change fonts */
14+
font-family: "rsc" !important;
15+
speak: never;
16+
font-style: normal;
17+
font-weight: normal;
18+
font-variant: normal;
19+
text-transform: none;
20+
line-height: 1;
21+
22+
/* Better Font Rendering =========== */
23+
-webkit-font-smoothing: antialiased;
24+
-moz-osx-font-smoothing: grayscale;
25+
}
26+
27+
.rsc-icon-error:before {
28+
content: "\e900";
29+
}
30+
.rsc-icon-warning:before {
31+
content: "\e901";
32+
}
33+
.rsc-icon-call:before {
34+
content: "\e902";
35+
}
36+
.rsc-icon-add_circle:before {
37+
content: "\e903";
38+
}
39+
.rsc-icon-add_circle_outline:before {
40+
content: "\e904";
41+
}
42+
.rsc-icon-clear:before {
43+
content: "\e905";
44+
}
45+
.rsc-icon-drafts:before {
46+
content: "\e906";
47+
}
48+
.rsc-icon-remove_circle:before {
49+
content: "\e907";
50+
}
51+
.rsc-icon-remove_circle_outline:before {
52+
content: "\e908";
53+
}
54+
.rsc-icon-local_grocery_store:before {
55+
content: "\e909";
56+
}
57+
.rsc-icon-arrow_back:before {
58+
content: "\e90a";
59+
}
60+
.rsc-icon-arrow_forward:before {
61+
content: "\e90b";
62+
}
63+
.rsc-icon-keyboard_control:before {
64+
content: "\e90c";
65+
}
66+
.rsc-icon-more_vert:before {
67+
content: "\e90d";
68+
}
69+
.rsc-icon-arrow_back_ios:before {
70+
content: "\e90e";
71+
}
72+
.rsc-icon-arrow_forward_ios:before {
73+
content: "\e90f";
74+
}
75+
.rsc-icon-check_box:before {
76+
content: "\e910";
77+
}
78+
.rsc-icon-check_box_outline_blank:before {
79+
content: "\e911";
80+
}
81+
.rsc-icon-star:before {
82+
content: "\e912";
83+
}
84+
.rsc-icon-star_half:before {
85+
content: "\e913";
86+
}
87+
.rsc-icon-star_outline:before {
88+
content: "\e914";
89+
}
90+
.rsc-icon-account_circle:before {
91+
content: "\e915";
92+
}
93+
.rsc-icon-check_circle:before {
94+
content: "\e916";
95+
}
96+
.rsc-icon-delete:before {
97+
content: "\e917";
98+
}
99+
.rsc-icon-search:before {
100+
content: "\e918";
101+
}

src/assets/scss/base/_index.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
@import "variables";
22
@import "reset";
3+
@import "icons";

src/assets/scss/components/_form-control.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,11 @@
2222
border-color: $red;
2323
}
2424
}
25+
26+
.field-group {
27+
display: flex;
28+
justify-content: space-between;
29+
.form-group {
30+
flex-basis: 48%;
31+
}
32+
}

src/assets/scss/pages/_checkout.scss

Lines changed: 108 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,132 @@
1919
text-align: center;
2020
li {
2121
display: inline-block;
22-
border-bottom: 2px solid $gray-eighty;
22+
width: 120px;
2323
cursor: pointer;
24+
position: relative;
25+
&:after {
26+
content: "";
27+
width: 120px;
28+
height: 2px;
29+
background: $gray-eighty;
30+
display: block;
31+
position: absolute;
32+
bottom: 12px;
33+
z-index: -1;
34+
}
35+
&:first-child {
36+
&:after {
37+
width: 60px;
38+
left: 60px;
39+
}
40+
}
41+
&:last-child {
42+
&:after {
43+
width: 60px;
44+
}
45+
}
2446
h2 {
25-
padding: 16px 32px;
47+
padding: 16px 0;
2648
text-align: center;
2749
font-size: 16px;
50+
color: $gray-light;
51+
}
52+
i {
53+
font-size: 24px;
54+
color: lighten($gray-eighty, 10);
55+
border-radius: 15px;
56+
background: $white;
57+
border: 2px solid $gray-eighty;
58+
}
59+
&.done {
60+
color: lighten($primary-green, 0);
61+
i {
62+
color: lighten($primary-green, 0);
63+
}
64+
h2 {
65+
color: lighten($primary-green, 0);
66+
}
2867
}
2968
&.active {
30-
color: $primary-green;
31-
border-bottom-color: $primary-green;
69+
color: lighten($primary-green, 15);
70+
i {
71+
color: lighten($primary-green, 15);
72+
}
73+
h2 {
74+
color: lighten($primary-green, 15);
75+
}
3276
}
3377
}
3478
}
3579
.order-details {
36-
padding: 24px 0;
80+
padding: 24px;
81+
background: $white;
82+
margin: 24px 24px 24px 0;
83+
border-radius: 6px;
84+
z-index: 1;
85+
}
86+
87+
.detail-container {
88+
margin-top: 24px;
89+
h2 {
90+
margin: 32px 0;
91+
text-align: center;
92+
}
93+
.auth-message {
94+
text-align: center;
95+
padding: 48px 24px;
96+
border: 1px solid #fff;
97+
background: $gray-light-bg;
98+
margin-bottom: 24px;
99+
border-radius: 8px;
100+
p {
101+
margin-bottom: 24px;
102+
span {
103+
padding: 4px;
104+
background: $gray-dark-bg;
105+
border-radius: 4px;
106+
}
107+
}
108+
button {
109+
background: transparent;
110+
color: $primary-green;
111+
border: 1px solid $primary-green;
112+
border-radius: 8px;
113+
}
114+
}
115+
.actions {
116+
display: flex;
117+
justify-content: space-between;
118+
button {
119+
border-radius: 8px;
120+
height: 48px;
121+
i {
122+
font-size: 20px;
123+
vertical-align: middle;
124+
}
125+
&:first-child {
126+
background-color: transparent;
127+
color: $primary-green;
128+
}
129+
&:disabled {
130+
opacity: 0.5;
131+
cursor: not-allowed;
132+
}
133+
}
134+
}
37135
}
38136

39137
.order-summary {
40-
padding: 0 24px 24px 24px;
138+
padding: 24px;
41139
background: $white;
42140
margin: 24px 0;
43141
border-radius: 6px;
44142
h2 {
45143
padding: 16px;
144+
span {
145+
color: $gray-light;
146+
font-weight: normal;
147+
}
46148
}
47149
.cart-items {
48150
width: 300px;

src/constants/common.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const phoneRegExp = /^((\\+[1-9]{1,4}[ \\-]*)|(\\([0-9]{2,3}\\)[ \\-]*)|([0-9]{2,4})[ \\-]*)*?[0-9]{3,4}?[ \\-]*[0-9]{3,4}?$/;

src/contexts/checkout.jsx

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import React, { useReducer, createContext, useEffect } from "react";
2+
import useLocalStorage from "hooks/useLocalStorage";
3+
4+
export const CHECKOUT_STEPS = {
5+
AUTH: "auth",
6+
SHIPPING: "shipping",
7+
PAYMENT: "payment"
8+
};
9+
10+
const initialState = {
11+
step: CHECKOUT_STEPS.AUTH,
12+
shippingAddress: null
13+
};
14+
15+
export const CheckoutStateContext = createContext();
16+
export const CheckoutDispatchContext = createContext();
17+
18+
const reducer = (state, action) => {
19+
switch (action.type) {
20+
case "SET_CHECKOUT_STEP":
21+
return {
22+
...state,
23+
step: action.payload.step
24+
};
25+
case "SET_SHIPPING_ADDRESS":
26+
return {
27+
...state,
28+
shippingAddress: action.payload.shippingAddress
29+
};
30+
default:
31+
throw new Error(`Unknown action: ${action.type}`);
32+
}
33+
};
34+
35+
const CheckoutProvider = ({ children }) => {
36+
const [checkoutState, setCheckoutState] = useLocalStorage("checkout", null);
37+
const persistedCheckoutState = {
38+
...initialState,
39+
shippingAddress: checkoutState || {}
40+
};
41+
const [state, dispatch] = useReducer(reducer, persistedCheckoutState);
42+
43+
useEffect(() => {
44+
setCheckoutState(state.shippingAddress);
45+
}, [state.shippingAddress]);
46+
return (
47+
<CheckoutDispatchContext.Provider value={dispatch}>
48+
<CheckoutStateContext.Provider value={state}>
49+
{children}
50+
</CheckoutStateContext.Provider>
51+
</CheckoutDispatchContext.Provider>
52+
);
53+
};
54+
55+
export const setCheckoutStep = (dispatch, step) => {
56+
return dispatch({
57+
type: "SET_CHECKOUT_STEP",
58+
payload: {
59+
step
60+
}
61+
});
62+
};
63+
64+
export const saveShippingAddress = (dispatch, shippingAddress) => {
65+
dispatch({
66+
type: "SET_SHIPPING_ADDRESS",
67+
payload: {
68+
shippingAddress
69+
}
70+
});
71+
return setCheckoutStep(dispatch, CHECKOUT_STEPS.PAYMENT);
72+
};
73+
74+
export default CheckoutProvider;

0 commit comments

Comments
 (0)