This commit is contained in:
Steve Chalco
2022-08-07 20:32:49 -07:00
parent 724ce2beb7
commit 3fbf2f59a6
13 changed files with 106 additions and 78 deletions

View File

@@ -1,11 +1,9 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import type { OnDeckState } from '../types';
const initialState: OnDeckState = {
profile: {
name: '',
product: ''
product: 'dropin'
},
checkout: {},
local: {},
@@ -30,9 +28,9 @@ export const onDeckSlice = createSlice({
updateSessionsInfo: (state, action: PayloadAction<OnDeckState>) => {
return { ...state, sessions: action.payload };
},
updateRedirectInfo: (state, action: PayloadAction<any>) => {
updateRedirectInfo: (state, action: PayloadAction<any>) => {
return { ...state, isRedirect: action.payload };
},
},
clearOnDeckInfo: state => {
return initialState;
}

View File

@@ -5,8 +5,8 @@ import { CheckoutBuilder, PaymentsForm, ComponentBase } from '.';
const ApplicationRouter = () => {
return (
<Routes>
<Route path="/checkout-builder" element={<CheckoutBuilder />} />
<Route path="/checkout-builder/:component" element={<ComponentBase />} />
<Route path="/" element={<CheckoutBuilder />} />
<Route path="/:component" element={<ComponentBase />} />
</Routes>
);
};

View File

@@ -5,14 +5,8 @@ import { Editor } from './configSteps/Editor';
import type { ConfigPropTypes, UpdateConfig } from './types';
import { Content } from './configSteps/Content';
const content = {
title: 'Profile',
version: 'Web Components/Drop-in v5.19.0',
description:
'The SDK instance accepts parameters related to itself. You must set global or component-specific configuration either on the locally on the main instance, globally through the AdyenCheckout , or in API request. Create and store a configuration profile for future use.'
};
export const Config = ({ configuration, descriptors, step, setActiveStep, action, updateStore }: ConfigPropTypes) => {
export const Config = ({ configuration, descriptors, step, setActiveStep, action, updateStore, content }: ConfigPropTypes) => {
const { profilePageContent } = content;
const handleUpdateConfig: UpdateConfig = (item, value, current): void => {
let newConfig = { ...configuration };
@@ -33,20 +27,8 @@ export const Config = ({ configuration, descriptors, step, setActiveStep, action
return (
<Fragment>
<Content title={content.title} version={content.version} description={content.description} />
<Grid mt={2} container>
<Grid item xs={8}>
<Typography pb={2} variant="body1" gutterBottom>
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec velit neque, auctor sit amet aliquam vel,
ullamcorper sit amet ligula. Praesent sapien massa, convallis a pellentesque nec, egestas non nisi. Pellentesque in ipsum id orci porta
dapibus.
</Typography>
</Grid>
<Grid item xs={8}>
<Typography variant="overline" gutterBottom>
<Box sx={{ fontSize: 16, fontWeight: 'medium' }}>Parameters</Box>
</Typography>
<Divider />
</Grid>
<Grid item xs={8}>
<ListOptions descriptors={descriptors} configuration={configuration} handleUpdateConfig={handleUpdateConfig} />
</Grid>
@@ -63,7 +45,9 @@ export const Config = ({ configuration, descriptors, step, setActiveStep, action
<Grid item xs={1}>
<Grid p={1} sx={{ height: '100%' }} direction="row" container justifyContent="space-between" alignItems="flex-end">
<Grid item>
<Button sx={{bgcolor:'#0abf53'}} variant="contained">Edit</Button>
<Button sx={{ bgcolor: '#0abf53' }} variant="contained">
Edit
</Button>
</Grid>
<Grid item>
<NavButtons step={step} setActiveStep={setActiveStep} configuration={configuration} />

View File

@@ -10,6 +10,7 @@ import type { ActionCreatorWithPayload } from '@reduxjs/toolkit';
import { useState } from 'react';
import { useSelector } from 'react-redux';
import { onDeckActions } from '../../app';
import content from '../../helpers/content.json';
import { useAppDispatch, useRedirect } from '../../hooks';
import type { RootState } from '../../store';
import { Config } from './Config';
@@ -23,11 +24,12 @@ const ColorlibStepIconRoot = styled('div')<{
}>(({ theme, ownerState }) => ({
color: theme.palette.grey[700],
zIndex: 1,
width: 50,
height: 50,
display: 'flex',
borderRadius: '50%',
justifyContent: 'center',
padding:0,
margin:0,
alignItems: 'center',
...((ownerState.active || ownerState.completed) && {
color: '#0066ff'
@@ -36,7 +38,10 @@ const ColorlibStepIconRoot = styled('div')<{
export const ConfigWrapper = () => {
const descriptors = useSelector((state: RootState) => state.descriptors);
const [activeStep, setActiveStep] = useState(0);
const steps = ['Profile', 'Global', 'Component', 'API', 'Review'];
let displayStep;
const { profile, checkout, local, sessions } = useSelector((state: RootState) => state.onDeck);
useRedirect({ profile, checkout, local, sessions }, setActiveStep);
@@ -45,8 +50,7 @@ export const ConfigWrapper = () => {
dispatch(action(value));
};
const steps = ['Profile', 'Global', 'Component', 'API', 'Review'];
let displayStep;
const { profilePageContent, globalPageContent, localPageContent, apiPageContent, reviewPageContent }: any = content;
console.log('STORE', JSON.stringify({ profile, checkout, local, sessions }));
@@ -60,6 +64,7 @@ export const ConfigWrapper = () => {
setActiveStep={setActiveStep}
action={updateProfileInfo}
updateStore={updateStore}
content={profilePageContent}
/>
);
break;
@@ -73,6 +78,7 @@ export const ConfigWrapper = () => {
setActiveStep={setActiveStep}
action={updateCheckoutInfo}
updateStore={updateStore}
content={globalPageContent}
/>
);
break;
@@ -86,6 +92,7 @@ export const ConfigWrapper = () => {
setActiveStep={setActiveStep}
action={updateLocalInfo}
updateStore={updateStore}
content={localPageContent}
/>
);
break;
@@ -99,11 +106,20 @@ export const ConfigWrapper = () => {
setActiveStep={setActiveStep}
action={updateSessionsInfo}
updateStore={updateStore}
content={apiPageContent}
/>
);
break;
case 4:
displayStep = <ReviewForm key="review" step={activeStep} setActiveStep={setActiveStep} configuration={{ checkout, local, sessions }} />;
displayStep = (
<ReviewForm
key="review"
step={activeStep}
setActiveStep={setActiveStep}
configuration={{ checkout, local, sessions }}
content={reviewPageContent}
/>
);
break;
case 5:
displayStep = (
@@ -135,17 +151,17 @@ export const ConfigWrapper = () => {
};
return (
<Grid container>
<Grid item xs={9} mt={2}>
<Stepper activeStep={activeStep} sx={{ pt: 3, pb: 5 }}>
<Grid justifyContent="center" container>
<Grid item xs={6} mt={4} mb={4}>
<Stepper activeStep={activeStep}>
{steps.map(label => (
<Step key={label}>
<StepLabel StepIconComponent={ColorlibStepIcon}/>
<StepLabel StepIconComponent={ColorlibStepIcon} />
</Step>
))}
</Stepper>
</Grid>
<Grid item xs={12}>
<Grid item xs={8}>
{displayStep}
</Grid>
</Grid>

View File

@@ -10,35 +10,35 @@ interface ContentProps {
export const Content = ({ title, version, description }: ContentProps) => {
return (
<Grid spacing={1} mt={2} container>
<Grid item xs={9}>
<Grid item xs={12}>
<Typography
component={'span'}
p={0.7}
sx={{ bgcolor: '#e6f8ed', borderColor: '#cef2dd', color: '#055f29', borderRadius: '5px' }}
variant="h6"
>
SDK Builder
SDK Explorer
</Typography>
<Typography component={'span'} p={0.7} variant="h5">
{title}
</Typography>
</Grid>
<Grid item xs={9}>
<Grid item xs={12}>
<Typography component={'span'} p={0.7} variant="caption">
{version}
</Typography>
</Grid>
<Grid item xs={9}>
<Grid item xs={12}>
<Typography mt={2} mb={3} variant="body2" gutterBottom>
{description}
</Typography>
</Grid>
<Grid item xs={9}>
<Grid item xs={12}>
<Typography variant="h4" gutterBottom>
<Box>Parameters</Box>
</Typography>
</Grid>
<Grid pb={2} item xs={9}>
<Grid pb={2} item xs={12}>
<Divider />
</Grid>
</Grid>

View File

@@ -50,7 +50,7 @@ export const NavButtons = ({ step, setActiveStep, configuration }: NavButtonsPro
</Button>
)}
<Button variant="contained" onClick={handleNext}>
{step === 4 ? 'Save Checkout' : 'Next'}
{step === 4 ? 'Export' : 'Next'}
</Button>
</Box>
);

View File

@@ -13,16 +13,11 @@ interface ProfileFormProps {
action: any;
updateStore: (value: any, action: ActionCreatorWithPayload<any>) => void;
setActiveStep: (step: number) => void;
content: any;
}
const content = {
title: 'Profile',
version: 'Web Components/Drop-in v5.19.0',
description:
'The SDK instance accepts parameters related to itself. You must set global or component-specific configuration either on the locally on the main instance, globally through the AdyenCheckout , or in API request. Create and store a configuration profile for future use.'
};
export const ProfileForm = ({ configuration, step, setActiveStep, action, updateStore }: ProfileFormProps) => {
export const ProfileForm = ({ configuration, step, setActiveStep, action, updateStore, content }: ProfileFormProps) => {
const { profilePageContent } = content;
const handleChange = (e: any) => {
updateStore({ [e.target.name]: e.target.value }, action);
};
@@ -31,6 +26,8 @@ export const ProfileForm = ({ configuration, step, setActiveStep, action, update
<Fragment>
<Content title={content.title} version={content.version} description={content.description} />
<Grid spacing={1} mt={2} container>
{/*
Commented out until we can begin to store config profiles in backend
<Grid item xs={7}>
<TextField
sx={{ borderRadius: '0' }}
@@ -42,8 +39,8 @@ export const ProfileForm = ({ configuration, step, setActiveStep, action, update
onChange={handleChange}
/>
<FormHelperText>Required</FormHelperText>
</Grid>
<Grid item xs={7}>
</Grid> */}
<Grid item xs={8}>
<FormControl fullWidth>
<InputLabel>Product</InputLabel>
<Select
@@ -54,28 +51,29 @@ export const ProfileForm = ({ configuration, step, setActiveStep, action, update
value={configuration.product}
onChange={handleChange}
label="Product"
defaultValue="dropin"
>
<MenuItem value={'dropin'}>dropin</MenuItem>
</Select>
</FormControl>
<FormHelperText>Required</FormHelperText>
</Grid>
</Grid>
<Grid
direction="column"
justifyContent="space-between"
alignItems="stretch"
container
sx={{ position: 'fixed', top: 0, right: 0, height: '100vh', bgcolor: 'secondary.main', width: '28%' }}
>
<Grid item xs={10} sx={{ height: '90%' }}>
<JSONInput viewOnly={true} placeholder={configuration} colors={dark_vscode_tribute} locale={localeEn} height="100%" width="100%" />
</Grid>
<Grid item xs={1}>
<Grid p={1} sx={{ height: '100%' }} direction="row" container justifyContent="flex-end" alignItems="flex-end">
<Grid item>
<NavButtons step={step} setActiveStep={setActiveStep} configuration={configuration} />
<Grid item xs={4}>
<Grid
direction="column"
justifyContent="space-between"
alignItems="stretch"
container
sx={{ position: 'fixed', top: 0, right: 0, height: '100vh', bgcolor: 'secondary.main', width: '28%' }}
>
<Grid item xs={10} sx={{ height: '90%' }}>
<JSONInput viewOnly={true} placeholder={configuration} colors={dark_vscode_tribute} locale={localeEn} height="100%" width="100%" />
</Grid>
<Grid item xs={1}>
<Grid p={1} sx={{ height: '100%' }} direction="row" container justifyContent="flex-end" alignItems="flex-end">
<Grid item>
<NavButtons step={step} setActiveStep={setActiveStep} configuration={configuration} />
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>

View File

@@ -1,19 +1,22 @@
import { Grid, Box, Divider, Button } from '@mui/material';
import { Grid } from '@mui/material';
import React from 'react';
import JSONInput from 'react-json-editor-ajrm';
import { dark_vscode_tribute, localeEn } from '../../../helpers/jsonEditor';
import ComponentBase from '../../ComponentBase/ComponentBase';
import { Content } from './Content';
import { NavButtons } from './NavButtons';
import React from 'react';
type ReviewFormProps = {
configuration: object;
step: number;
setActiveStep: (step: number) => void;
content: any;
};
export const ReviewForm = ({ configuration, step, setActiveStep }: ReviewFormProps) => {
export const ReviewForm = ({ configuration, step, setActiveStep, content }: ReviewFormProps) => {
return (
<React.Fragment>
<Content title={content.title} version={content.version} description={content.description} />
<Grid mt={2} container>
<Grid item xs={8}>
<ComponentBase />

View File

@@ -9,6 +9,7 @@ export interface ConfigPropTypes {
action: ActionCreatorWithPayload<any>;
updateStore: (value: any, action: any) => void;
setActiveStep: (step: number) => void;
content?: any;
}
export type UpdateConfig = (key: string, value: string | null, current?: any) => void;

View File

@@ -0,0 +1,27 @@
{
"profilePageContent": {
"title": "Profile",
"version": "Web Components/Drop-in v5.19.0",
"description": "The SDK instance accepts parameters related to itself. You must set global or component-specific configuration either locally or on the main instance, globally through the AdyenCheckout , or in API request. Build and export a configuration profile for future use."
},
"globalPageContent": {
"title": "Checkout",
"version": "Web Components/Drop-in v5.19.0",
"description": "The SDK instance accepts parameters related to itself. You must set global or component-specific configuration either locally or on the main instance, globally through the AdyenCheckout , or in API request. Build and export a configuration profile for future use."
},
"localPageContent": {
"title": "Local",
"version": "Web Components/Drop-in v5.19.0",
"description": "The SDK instance accepts parameters related to itself. You must set global or component-specific configuration either locally or on the main instance, globally through the AdyenCheckout , or in API request. Build and export a configuration profile for future use."
},
"apiPageContent": {
"title": "API",
"version": "Web Components/Drop-in v5.19.0",
"description": "The SDK instance accepts parameters related to itself. You must set global or component-specific configuration either locally or on the main instance, globally through the AdyenCheckout , or in API request. Build and export a configuration profile for future use."
},
"reviewPageContent": {
"title": "Review",
"version": "Web Components/Drop-in v5.19.0",
"description": "The SDK instance accepts parameters related to itself. You must set global or component-specific configuration either locally or on the main instance, globally through the AdyenCheckout , or in API request. Build and export a configuration profile for future use."
}
}

View File

@@ -35,7 +35,8 @@ export const isEmpty = (x: object) => {
};
export const isConfigEmpty = (x: object) => {
const emptyConfig = { profile: { name: '', product: '' }, checkout: {}, local: {}, sessions: {} };
const defaultProduct = 'dropin';
const emptyConfig = { profile: { product: defaultProduct }, checkout: {}, local: {}, sessions: {} };
return deepEqual(emptyConfig, x);
};

View File

@@ -15,7 +15,7 @@ export const useInitializeSession = ({ configuration, endpoint }: { configuratio
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({ ...sessions, returnUrl: `${CLIENT_URL}/checkout-builder` })
body: JSON.stringify({ ...sessions, returnUrl: `${CLIENT_URL}/` })
};
const initialize: () => void = async () => {
try {

View File

@@ -21,10 +21,10 @@ app.use(function (req, res, next) {
const root = path.join(__dirname, '../client', 'build');
app.use(express.static(root));
app.get('/checkout-builder', (req, res) => {
app.get('/', (req, res) => {
res.sendFile('index.html', { root });
});
app.get('/checkout-builder/dropin', (req, res) => {
app.get('/dropin', (req, res) => {
res.sendFile('index.html', { root });
});