0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Static Stripe Connect flow in AdminX (#17432)

refs. https://github.com/TryGhost/Product/issues/3608

- Basic static components are needed for Stripe Connect flow
- The current Stripe Connect flow has quite a lot of visual issues and
also the UX is somewhat messy
This commit is contained in:
Peter Zimon 2023-07-20 17:17:17 +02:00 committed by GitHub
parent bb34683af2
commit 78a06aead3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 258 additions and 1 deletions

View file

@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" stroke-width="1.5"><path d="M5.25 12.373h-3" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="m5.25 15.373-1.5 1.5" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="m5.25 9.373-1.5-1.5" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="M18.75 12.373h3" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="m18.75 15.373 1.5 1.5" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="m18.75 9.373 1.5-1.5" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.25 9.373v-4.5A3.762 3.762 0 0 1 12 1.123h0a3.761 3.761 0 0 1 3.75 3.75v5.25a3.763 3.763 0 0 1-2.25 3.435 3.709 3.709 0 0 1-1.5.315" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="M15.75 14.623v4.5a3.76 3.76 0 0 1-3.75 3.75h0a3.761 3.761 0 0 1-3.75-3.75v-4.5a3.762 3.762 0 0 1 3.75-3.75" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -54,6 +54,13 @@ export const WithLabelAndHint: Story = {
}
};
export const CustomLabelStyle: Story = {
args: {
label: 'Check me',
labelClasses: 'text-sm translate-y-[1px]'
}
};
export const LeftToRight: Story = {
args: {
label: 'Check me',
@ -71,6 +78,12 @@ export const WithSeparator: Story = {
}
};
export const CustomBgColor: Story = {
args: {
toggleBg: 'stripetest'
}
};
export const Error: Story = {
args: {
label: 'Check me',

View file

@ -1,5 +1,6 @@
import React, {useId} from 'react';
import Separator from '../Separator';
import clsx from 'clsx';
import {Heading6Styles} from '../Heading';
type ToggleSizes = 'sm' | 'md' | 'lg';
@ -12,6 +13,8 @@ interface ToggleProps {
size?: ToggleSizes;
label?: React.ReactNode;
labelStyle?: 'heading' | 'value';
labelClasses?: string;
toggleBg?: 'green' | 'stripetest';
separator?: boolean;
direction?: ToggleDirections;
hint?: React.ReactNode;
@ -23,6 +26,8 @@ const Toggle: React.FC<ToggleProps> = ({
direction,
label,
labelStyle = 'value',
labelClasses,
toggleBg = 'green',
hint,
separator,
error,
@ -50,15 +55,31 @@ const Toggle: React.FC<ToggleProps> = ({
break;
}
labelStyles = clsx(
labelClasses,
labelStyles
);
if (labelStyle === 'heading') {
direction = 'rtl';
}
let toggleBgClass;
switch (toggleBg) {
case 'stripetest':
toggleBgClass = 'checked:bg-[#EC6803]';
break;
default:
toggleBgClass = 'checked:bg-green';
break;
}
return (
<div>
<div className={`group flex items-start gap-2 ${direction === 'rtl' && 'justify-between'} ${separator && 'pb-2'}`}>
<input checked={checked}
className={`appearance-none rounded-full bg-grey-300 transition after:absolute after:ml-0.5 after:mt-0.5 after:rounded-full after:border-none after:bg-white after:transition-[background-color_0.2s,transform_0.2s] after:content-[''] checked:bg-green checked:after:absolute checked:after:rounded-full checked:after:border-none checked:after:bg-white checked:after:transition-[background-color_0.2s,transform_0.2s] checked:after:content-[''] hover:cursor-pointer group-hover:bg-grey-400 checked:group-hover:bg-green-600 ${sizeStyles} ${direction === 'rtl' && ' order-2'}`}
className={`${toggleBgClass} appearance-none rounded-full bg-grey-300 transition after:absolute after:ml-0.5 after:mt-0.5 after:rounded-full after:border-none after:bg-white after:transition-[background-color_0.2s,transform_0.2s] after:content-[''] checked:after:absolute checked:after:rounded-full checked:after:border-none checked:after:bg-white checked:after:transition-[background-color_0.2s,transform_0.2s] checked:after:content-[''] hover:cursor-pointer group-hover:opacity-80 ${sizeStyles} ${direction === 'rtl' && ' order-2'}`}
id={id}
role="switch"
type="checkbox"

View file

@ -0,0 +1,22 @@
import type {Meta, StoryObj} from '@storybook/react';
import StripeButton from './StripeButton';
const meta = {
title: 'Settings / Stripe Button',
component: StripeButton,
tags: ['autodocs']
} satisfies Meta<typeof StripeButton>;
export default meta;
type Story = StoryObj<typeof StripeButton>;
export const Default: Story = {
args: { }
};
export const CustomLabel: Story = {
args: {
label: 'Let\'s go'
}
};

View file

@ -0,0 +1,24 @@
import Button, {ButtonProps} from '../global/Button';
import React from 'react';
import clsx from 'clsx';
interface StripeButtonProps {
label?: React.ReactNode;
}
const StripeButton: React.FC<StripeButtonProps | ButtonProps> = ({label, ...props}) => {
const classNames = clsx(
'cursor-pointer rounded-md bg-[#625BF6] font-semibold text-white transition-all hover:opacity-90',
label ? 'px-5 py-2 text-sm' : 'px-6 py-[9px]'
);
if (!label) {
label = <svg fill='none' height='16' width='132' xmlns='http://www.w3.org/2000/svg'><g clipPath='url(#clip0_1443_3527)' fill='#fff'><path d='M2 7.6c0-2.3 1.3-3.9 3-3.9 1.3 0 2.2.8 2.5 2l1.8-.6C8.7 3.2 7.2 2 5 2 2.1 2 0 4.3 0 7.6s2.1 5.6 5 5.6c2.2 0 3.7-1.2 4.3-3.1l-1.8-.6c-.3 1.3-1.2 2-2.5 2-1.8 0-3-1.6-3-3.9zm15.6 1.5C17.6 6.7 16 5 13.8 5 11.6 5 10 6.6 10 9.1c0 2.5 1.6 4.1 3.8 4.1 2.3 0 3.8-1.7 3.8-4.1zm-5.7 0c0-1.6.8-2.6 2-2.6s2 1 2 2.6-.8 2.6-2 2.6-2-1-2-2.6zM19 13h1.8V8.4c0-1.1.8-1.7 1.6-1.7 1 0 1.4.7 1.4 1.7V13h1.8V7.8c0-1.7-1-2.8-2.6-2.8-1 0-1.7.5-2.2 1v-.8H19V13zm8.5 0h1.8V8.4c0-1.1.8-1.7 1.6-1.7 1 0 1.4.7 1.4 1.7V13h1.8V7.8c0-1.7-1-2.8-2.6-2.8-1 0-1.7.5-2.2 1v-.8h-1.8V13zm11.8.2c1.6 0 2.8-.8 3.4-2.2l-1.5-.6c-.2.8-.9 1.3-1.8 1.3-1.2 0-2-.8-2.1-2.2h5.5v-.6c0-2.2-1.2-3.9-3.5-3.9-2.2 0-3.8 1.8-3.8 4.1 0 2.4 1.5 4.1 3.8 4.1zm-.1-6.7c1.1 0 1.7.8 1.7 1.6h-3.6c.2-1.1 1-1.6 1.9-1.6zm6.2 2.6c0-1.6.8-2.5 2.1-2.5 1 0 1.5.6 1.8 1.5l1.5-.8c-.4-1.3-1.6-2.2-3.3-2.2-2.2 0-3.9 1.7-3.9 4.1 0 2.4 1.6 4.1 3.9 4.1 1.7 0 2.9-1 3.3-2.3l-1.5-.8c-.2.9-.8 1.5-1.8 1.5-1.3-.1-2.1-1-2.1-2.6zM52 11c0 1.6.8 2.1 2.3 2.1.5 0 .9 0 1.2-.1v-1.5h-.7c-.6 0-1.1-.1-1.1-.8V6.6h1.7V5.1h-1.7V2.8h-1.8v2.3h-1.1v1.5h1.1L52 11zm11.7-5.9l-1.4 5.2-1.4-5.2h-1.8l2.4 7.9h1.6l1.4-5.2 1.4 5.2h1.6l2.4-7.9h-1.8l-1.5 5.2-1.4-5.2h-1.5zm7.1-1h1.8V2.3h-1.9l.1 1.8zm1.8 1h-1.8V13h1.8V5.1zm2 5.9c0 1.6.8 2.1 2.3 2.1.5 0 .9 0 1.2-.1v-1.5h-.7c-.6 0-1.1-.1-1.1-.8V6.6H78V5.1h-1.7V2.8h-1.7v2.3h-1.1v1.5h1.1V11zm4.9 2h1.8V8.4c0-1.1.8-1.7 1.6-1.7 1 0 1.4.7 1.4 1.7V13h1.8V7.8c0-1.7-1-2.8-2.6-2.8-1 0-1.7.5-2.2 1V2.3h-1.8V13zM117.1 15.4v-3c.4.3.9.7 1.9.7 1.9 0 3.6-1.5 3.6-4.9 0-3.1-1.7-4.8-3.6-4.8-1 0-1.7.5-2.1.9l-.1-.6h-2.3V16l2.6-.6zm1.2-9.7c1 0 1.6 1.1 1.6 2.5 0 1.5-.6 2.5-1.6 2.5-.6 0-1-.2-1.3-.5v-4c.4-.2.7-.5 1.3-.5zM127.701 13.2c1.3 0 2.2-.3 3-.7v-2.2c-.7.4-1.5.6-2.6.6s-1.9-.4-2.1-1.7h5.2v-1c0-2.8-1.3-4.9-3.8-4.9s-4.1 2.2-4.1 4.9c0 3.3 1.8 5 4.4 5zm-.3-7.7c.6 0 1.3.5 1.3 1.7h-2.8c.1-1.1.8-1.7 1.5-1.7zM107.6 6.5c.6-.9 1.7-.7 2-.6V3.4c-.4-.1-1.6-.4-2.1.8l-.2-.8H105v9.4h2.6V6.5zM95.602 10.2c0 .5-.4.6-1 .6-.9 0-2-.4-2.9-.9v2.6c1 .4 2 .6 2.9.6 2.2 0 3.7-1.1 3.7-3 0-3.2-4-2.6-4-3.8 0-.4.3-.6.9-.6.8 0 1.8.2 2.6.7V3.8c-.9-.4-1.7-.5-2.6-.5-2.1 0-3.6 1.1-3.6 3 0 3.1 4 2.6 4 3.9zM102.001 13.2c.8 0 1.5-.2 1.9-.4v-2.2c-.3.1-2 .6-2-1V5.8h2V3.5h-2V1.2l-2.6.6v8.6c0 1.6 1.1 2.8 2.7 2.8zM110.5.6v2.1l2.7-.5V0l-2.7.6zM113.1 3.5h-2.6v9.3h2.6V3.5z'/></g><defs><clipPath id='clip0_1443_3527'><path d='M0 0h132v16H0z' fill='#fff'/></clipPath></defs></svg>;
}
return (
<Button className={classNames} label={label} unstyled {...props} />
);
};
export default StripeButton;

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400" style="enable-background:new 0 0 400 400" xml:space="preserve"><path style="fill-rule:evenodd;clip-rule:evenodd;fill:#635bff" d="M0 0h400v400H0z"/><path d="M184.4 155.5c0-9.4 7.7-13.1 20.5-13.1 18.4 0 41.6 5.6 60 15.5v-56.8C244.8 93.1 225 90 205 90c-49.1 0-81.7 25.6-81.7 68.4 0 66.7 91.9 56.1 91.9 84.9 0 11.1-9.7 14.7-23.2 14.7-20.1 0-45.7-8.2-66-19.3v57.5c22.5 9.7 45.2 13.8 66 13.8 50.3 0 84.9-24.9 84.9-68.2-.4-72-92.5-59.2-92.5-86.3z" style="fill-rule:evenodd;clip-rule:evenodd;fill:#fff"/></svg>

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View file

@ -0,0 +1,3 @@
<svg width="154" height="14" viewBox="0 0 154 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M69.79 4.12L67.1 11H65.66L62.96 4.12H64.67L66.38 8.75L68.09 4.12H69.79ZM70.57 11V4.12H74.91V5.48H72.24V6.85H74.52V8.16H72.24V9.64H74.99V11H70.57ZM77.91 5.44V7.26H78.67C79.24 7.26 79.65 6.87 79.65 6.35C79.65 5.81 79.24 5.44 78.67 5.44H77.91ZM76.28 11V4.12H78.89C80.31 4.12 81.32 5.04 81.32 6.35C81.32 7.24 80.85 7.96 80.06 8.34L81.59 11H79.81L78.47 8.57H77.91V11H76.28ZM82.68 11V4.12H84.35V11H82.68ZM85.99 11V4.12H90.33V5.48H87.66V7.11H89.94V8.47H87.66V11H85.99ZM91.46 11V4.12H93.13V11H91.46ZM94.77 11V4.12H99.11V5.48H96.44V6.85H98.72V8.16H96.44V9.64H99.19V11H94.77ZM100.48 11V4.12H103.21C105.2 4.12 106.61 5.55 106.61 7.56C106.61 9.57 105.2 11 103.21 11H100.48ZM102.15 5.48V9.64H103.13C104.18 9.64 104.91 8.79 104.91 7.56C104.91 6.33 104.18 5.48 103.13 5.48H102.15ZM110.32 11V4.12H112.97C114.41 4.12 115.43 5.06 115.43 6.39C115.43 7.72 114.41 8.64 112.97 8.64H111.95V11H110.32ZM111.95 5.44V7.33H112.75C113.34 7.33 113.77 6.94 113.77 6.39C113.77 5.82 113.34 5.44 112.75 5.44H111.95ZM115.07 11L117.77 4.12H119.21L121.9 11H120.28L119.75 9.58H117.22L116.7 11H115.07ZM118.49 6.13L117.68 8.34H119.29L118.49 6.13ZM124.31 5.44V7.26H125.07C125.64 7.26 126.05 6.87 126.05 6.35C126.05 5.81 125.64 5.44 125.07 5.44H124.31ZM122.68 11V4.12H125.29C126.71 4.12 127.72 5.04 127.72 6.35C127.72 7.24 127.25 7.96 126.46 8.34L127.99 11H126.21L124.87 8.57H124.31V11H122.68ZM130.32 11V5.48H128.33V4.12H133.96V5.48H131.98V11H130.32ZM135.02 11V4.12H136.46L139.56 8.36V4.12H141.11V11H139.67L136.58 6.76V11H135.02ZM142.75 11V4.12H147.09V5.48H144.42V6.85H146.7V8.16H144.42V9.64H147.17V11H142.75ZM150.09 5.44V7.26H150.85C151.42 7.26 151.83 6.87 151.83 6.35C151.83 5.81 151.42 5.44 150.85 5.44H150.09ZM148.46 11V4.12H151.07C152.49 4.12 153.5 5.04 153.5 6.35C153.5 7.24 153.03 7.96 152.24 8.34L153.77 11H151.99L150.65 8.57H150.09V11H148.46ZM41 3.068L55 0V10.935L41 14V3.068ZM46.323 9.537C46.4682 9.67288 46.6599 9.74814 46.8588 9.7474C47.0577 9.74665 47.2488 9.66996 47.393 9.533L51.207 5.869C51.2774 5.80109 51.3334 5.7197 51.3716 5.62966C51.4099 5.53963 51.4296 5.44282 51.4296 5.345C51.4296 5.24718 51.4099 5.15037 51.3716 5.06034C51.3334 4.9703 51.2774 4.88891 51.207 4.821C51.0622 4.68156 50.869 4.60365 50.668 4.60365C50.467 4.60365 50.2738 4.68156 50.129 4.821L46.859 7.95L45.873 7.05C45.7282 6.91056 45.535 6.83265 45.334 6.83265C45.133 6.83265 44.9398 6.91056 44.795 7.05C44.7243 7.11776 44.6681 7.19911 44.6297 7.28916C44.5913 7.37921 44.5715 7.4761 44.5715 7.574C44.5715 7.6719 44.5913 7.76879 44.6297 7.85884C44.6681 7.94889 44.7243 8.03024 44.795 8.098L46.323 9.537ZM32.97 8.07H28.542C28.642 9.163 29.419 9.485 30.301 9.485C31.2 9.485 31.907 9.291 32.524 8.969V10.849C31.909 11.2 31.097 11.454 30.016 11.454C27.812 11.454 26.268 10.031 26.268 7.217C26.268 4.841 27.578 2.954 29.73 2.954C31.88 2.954 33 4.84 33 7.23C33 7.455 32.98 7.944 32.97 8.07ZM29.716 4.856C29.15 4.856 28.521 5.296 28.521 6.348H30.861C30.861 5.298 30.271 4.856 29.716 4.856ZM22.679 11.454C21.888 11.454 21.404 11.109 21.079 10.864L21.074 13.504L18.812 14L18.811 3.11H20.803L20.921 3.686C21.1536 3.45305 21.43 3.26844 21.7343 3.14281C22.0386 3.01718 22.3648 2.95301 22.694 2.954C24.282 2.954 25.779 4.43 25.779 7.146C25.779 10.111 24.299 11.454 22.679 11.454ZM22.153 5.02C21.633 5.02 21.308 5.216 21.073 5.483L21.086 8.95C21.305 9.195 21.622 9.393 22.153 9.393C22.989 9.393 23.55 8.453 23.55 7.197C23.55 5.977 22.98 5.02 22.153 5.02ZM15.615 3.11H17.886V11.287H15.616V3.109L15.615 3.11ZM15.615 0.498L17.885 0V1.9L15.615 2.398V0.498ZM13.269 5.743V11.287H11.007V3.109H12.963L13.106 3.799C13.635 2.795 14.693 2.999 14.994 3.109V5.254C14.706 5.158 13.804 5.019 13.269 5.743ZM8.49398 8.418C8.49398 9.793 9.92098 9.365 10.211 9.245V11.145C9.90998 11.315 9.36298 11.454 8.62298 11.454C7.27998 11.454 6.27298 10.434 6.27298 9.053L6.28298 1.567L8.49198 1.083L8.49398 3.109H10.212V5.099H8.49398V8.418ZM5.74798 8.816C5.74798 10.496 4.45198 11.454 2.56998 11.454C1.78998 11.454 0.936976 11.298 0.0959759 10.924V8.697C0.855976 9.123 1.82298 9.442 2.57298 9.442C3.07698 9.442 3.44098 9.302 3.44098 8.872C3.44098 7.757 0.000976562 8.177 0.000976562 5.594C0.000976562 3.942 1.22498 2.954 3.05998 2.954C3.80998 2.954 4.55898 3.073 5.30798 3.381V5.578C4.61998 5.195 3.74598 4.978 3.05798 4.978C2.58398 4.978 2.28898 5.118 2.28898 5.483C2.28898 6.533 5.74798 6.034 5.74798 8.816Z" fill="#625BF6"/>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

@ -5,6 +5,7 @@ import NavigationModal from '../settings/site/NavigationModal';
import NiceModal from '@ebay/nice-modal-react';
import PortalModal from '../settings/membership/portal/PortalModal';
import React, {createContext, useCallback, useContext, useEffect, useState} from 'react';
import StripeConnectModal from '../settings/membership/stripe/StripeConnectModal';
import TierDetailModal from '../settings/membership/tiers/TierDetailModal';
import {SettingsContext} from './SettingsProvider';
@ -55,6 +56,8 @@ function handleNavigation() {
NiceModal.show(PortalModal);
} else if (pathName === 'tiers/add') {
NiceModal.show(TierDetailModal);
} else if (pathName === 'stripe-connect') {
NiceModal.show(StripeConnectModal);
}
const element = document.getElementById(pathName);
if (element) {

View file

@ -1,7 +1,9 @@
import React, {useState} from 'react';
import SettingGroup from '../../../admin-x-ds/settings/SettingGroup';
import StripeButton from '../../../admin-x-ds/settings/StripeButton';
import TabView from '../../../admin-x-ds/global/TabView';
import TiersList from './tiers/TiersList';
import useRouting from '../../../hooks/useRouting';
import {getActiveTiers, getArchivedTiers} from '../../../utils/helpers';
import {useTiers} from '../../providers/ServiceProvider';
@ -10,6 +12,11 @@ const Tiers: React.FC<{ keywords: string[] }> = ({keywords}) => {
const {data: tiers, update: updateTier} = useTiers();
const activeTiers = getActiveTiers(tiers);
const archivedTiers = getArchivedTiers(tiers);
const {updateRoute} = useRouting();
const openConnectModal = () => {
updateRoute('stripe-connect');
};
const tabs = [
{
@ -26,6 +33,7 @@ const Tiers: React.FC<{ keywords: string[] }> = ({keywords}) => {
return (
<SettingGroup
customButtons={<StripeButton onClick={openConnectModal}/>}
description='Set prices and paid member sign up settings'
keywords={keywords}
navid='tiers'

View file

@ -0,0 +1,161 @@
import BookmarkThumb from '../../../../assets/images/stripe-thumb.jpg';
import Button from '../../../../admin-x-ds/global/Button';
import GhostLogo from '../../../../assets/images/orb-squircle.png';
import GhostLogoPink from '../../../../assets/images/orb-pink.png';
import Heading from '../../../../admin-x-ds/global/Heading';
import Modal from '../../../../admin-x-ds/global/modal/Modal';
import NiceModal, {useModal} from '@ebay/nice-modal-react';
import React, {useState} from 'react';
import StripeButton from '../../../../admin-x-ds/settings/StripeButton';
import StripeLogo from '../../../../assets/images/stripe-emblem.svg';
import TextArea from '../../../../admin-x-ds/global/form/TextArea';
import Toggle from '../../../../admin-x-ds/global/form/Toggle';
import useRouting from '../../../../hooks/useRouting';
import {ReactComponent as StripeVerified} from '../../../../assets/images/stripe-verified.svg';
const Start: React.FC<{onNext?: () => void}> = ({onNext}) => {
return (
<div>
<div className='flex items-center justify-between'>
<Heading level={3}>Getting paid</Heading>
<StripeVerified />
</div>
<div className='mb-7 mt-6'>
Stripe is our exclusive direct payments partner. Ghost collects <strong>no fees</strong> on any payments! If you dont have a Stripe account yet, you can <a className='underline' href="https://stripe.com" rel="noopener noreferrer" target="_blank">sign up here</a>.
</div>
<StripeButton label={<>I have a Stripe account, let's go &rarr;</>} onClick={onNext} />
</div>
);
};
const Connect: React.FC<{
submitEnabled: boolean,
onSubmit?: () => void,
onEnterKey?: (event: React.ChangeEvent<HTMLTextAreaElement>) => void
onTestMode?: (event: React.ChangeEvent<HTMLInputElement>) => void;
testMode?: boolean;
}> = ({
submitEnabled = false,
onSubmit,
onEnterKey,
onTestMode,
testMode
}) => {
return (
<div>
<div className='mb-6 flex items-center justify-between'>
<Heading level={3}>Connect with Stripe</Heading>
<Toggle
direction='rtl'
label='Test mode'
labelClasses={`text-sm translate-y-[1px] ${testMode ? 'text-[#EC6803]' : 'text-grey-800'}`}
toggleBg='stripetest'
onChange={onTestMode}
/>
</div>
<Heading level={6} grey>Step 1 <span className='text-black'>Generate secure key</span></Heading>
<div className='mb-4 mt-2'>
Click on the <strong>Connect with Stripe</strong> button to generate a secure key that connects your Ghost site with Stripe.
</div>
<StripeButton onClick={() => {}} />
<Heading className='mb-2 mt-8' level={6} grey>Step 2 <span className='text-black'>Paste secure key</span></Heading>
<TextArea clearBg={false} placeholder='Paste your secure key here' onChange={onEnterKey}></TextArea>
{submitEnabled && <Button className='mt-5' color='green' label='Save Stripe settings' onClick={onSubmit} />}
</div>
);
};
const Connected: React.FC<{onClose?: () => void}> = ({onClose}) => {
return (
<section>
<div className='flex items-center justify-between'>
<Button icon='link-broken' label='Disconnect' link />
<Button icon='close' size='sm' link onClick={onClose} />
</div>
<div className='my-20 flex flex-col items-center'>
<div className='relative h-20 w-[200px]'>
<img alt='Ghost Logo' className='absolute left-10 h-16 w-16' src={GhostLogo} />
<img alt='Stripe Logo' className='absolute right-10 h-16 w-16 rounded-2xl shadow-[-1.5px_0_0_1.5px_#fff]' src={StripeLogo} />
</div>
<Heading level={3}>You are connected with Stripe!</Heading>
<div className='mt-1'>Connected to <strong>Dummy</strong></div>
</div>
<div className='flex flex-col items-center'>
<Heading level={6}>Read next</Heading>
<a className='w-100 mt-5 flex items-stretch justify-between border border-grey-200 transition-all hover:border-grey-400' href="https://ghost.org/resources/managing-your-stripe-account/?ref=admin" rel="noopener noreferrer" target="_blank">
<div className='p-4'>
<div className='font-bold'>How to setup and manage your Stripe account</div>
<div className='mt-1 text-sm text-grey-800'>Learn how to configure your Stripe account to work with Ghost, from custom branding to payment receipt emails.</div>
<div className='mt-3 flex items-center gap-1 text-sm text-grey-800'>
<img alt='Ghost Logo' className='h-4 w-4' src={GhostLogoPink} />
<strong>Ghost Resources</strong>
<span>&middot;</span>
<span>by Kym Ellis</span>
</div>
</div>
<div className='flex w-[200px] shrink-0 items-center justify-center overflow-hidden'>
<img alt="Bookmark Thumb" className='min-h-full min-w-full shrink-0' src={BookmarkThumb} />
</div>
</a>
</div>
</section>
);
};
const StripeConnectModal: React.FC = () => {
const {updateRoute} = useRouting();
const [step, setStep] = useState('start');
const [submitEnabled, setSubmitEnabled] = useState(false);
const [testMode, setTestMode] = useState(false);
const mainModal = useModal();
const next = () => {
switch (step) {
case 'connect':
setStep('connected');
break;
default:
setStep('connect');
break;
}
};
const enterKey = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setSubmitEnabled(Boolean(event.target.value));
};
const onTestMode = (event: React.ChangeEvent<HTMLInputElement>) => {
setTestMode(event.target.checked);
};
const close = () => {
mainModal.remove();
};
let contents;
switch (step) {
case 'connect':
contents = <Connect submitEnabled={submitEnabled} testMode={testMode} onEnterKey={enterKey} onSubmit={next} onTestMode={onTestMode} />;
break;
case 'connected':
contents = <Connected onClose={close} />;
break;
default:
contents = <Start onNext={next} />;
break;
}
return <Modal
afterClose={() => {
updateRoute('tiers');
}}
cancelLabel=''
footer={<></>}
size={step === 'connected' ? 740 : 520}
title=''
>
{contents}
</Modal>;
};
export default NiceModal.create(StripeConnectModal);