refactored ui add provider
This commit is contained in:
parent
d29499b80a
commit
9699510369
@ -1,13 +1,14 @@
|
|||||||
// import { FunctionalComponent, JSX } from 'preact';
|
|
||||||
// import styled from './preact-styled'
|
|
||||||
|
|
||||||
// import { css } from '@linaria/core';
|
// need to import linaria types, otherwise compiler will complain
|
||||||
|
import type * as Linaria from '@linaria/core';
|
||||||
|
|
||||||
import { styled } from '@linaria/react';
|
import { styled } from '@linaria/react';
|
||||||
|
|
||||||
export const PopupBox = styled.div`
|
export const PopupBox = styled.div`
|
||||||
height: calc(320px - 34px - 16px);
|
height: calc(320px - 34px - 16px);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
& > section {
|
& > section {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@ -22,9 +23,14 @@ export const PopupBox = styled.div`
|
|||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& > section > h1 {
|
||||||
|
margin-top: 0.3em;
|
||||||
|
margin-bottom: 0.3em;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const Button = styled.button`
|
export const Button = styled.button`
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
zoom: 1;
|
zoom: 1;
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
@ -50,7 +56,7 @@ const Button = styled.button`
|
|||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[disabled] {
|
&:disabled {
|
||||||
border: none;
|
border: none;
|
||||||
background-image: none;
|
background-image: none;
|
||||||
/* csslint ignore:start */
|
/* csslint ignore:start */
|
||||||
@ -113,6 +119,10 @@ export const Row = styled.div`
|
|||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const LightText = styled.div`
|
||||||
|
color: gray;
|
||||||
|
`
|
||||||
|
|
||||||
export const SmallText = styled.div`
|
export const SmallText = styled.div`
|
||||||
font-size: small;
|
font-size: small;
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
@ -133,3 +143,41 @@ export const CenteredTextBold = styled(CenteredText)`
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: ${((props: any): any => String(props.color) as any) as any};
|
color: ${((props: any): any => String(props.color) as any) as any};
|
||||||
`
|
`
|
||||||
|
export const Input = styled.div`
|
||||||
|
& label {
|
||||||
|
display: block;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
& input {
|
||||||
|
display: block;
|
||||||
|
padding: 5px;
|
||||||
|
width: calc(100% - 4px - 10px);
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const ErrorBox = styled.div`
|
||||||
|
border: 2px solid #f5c6cb;
|
||||||
|
border-radius: 0.25em;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-direction: column;
|
||||||
|
/* margin: 0.5em; */
|
||||||
|
padding-left: 1em;
|
||||||
|
padding-right: 1em;
|
||||||
|
width: "100%";
|
||||||
|
color: #721c24;
|
||||||
|
background: #f8d7da;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
& > button {
|
||||||
|
align-self: center;
|
||||||
|
font-size: 100%;
|
||||||
|
padding: 0;
|
||||||
|
height: 28px;
|
||||||
|
width: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
@ -23,8 +23,6 @@ function getJsonIfOk(r: Response) {
|
|||||||
|
|
||||||
export function ProviderAddPage({ onBack }: Props): VNode {
|
export function ProviderAddPage({ onBack }: Props): VNode {
|
||||||
const [verifying, setVerifying] = useState<{ url: string, provider: BackupBackupProviderTerms } | undefined>(undefined)
|
const [verifying, setVerifying] = useState<{ url: string, provider: BackupBackupProviderTerms } | undefined>(undefined)
|
||||||
const [readingTerms, setReadingTerms] = useState<boolean | undefined>(undefined)
|
|
||||||
const alreadyCheckedTheTerms = readingTerms === false
|
|
||||||
|
|
||||||
if (!verifying) {
|
if (!verifying) {
|
||||||
return <SetUrlView
|
return <SetUrlView
|
||||||
@ -38,22 +36,12 @@ export function ProviderAddPage({ onBack }: Props): VNode {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
if (readingTerms) {
|
|
||||||
return <TermsOfService
|
|
||||||
onCancel={() => setReadingTerms(undefined)}
|
|
||||||
onAccept={() => setReadingTerms(false)}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
return <ConfirmProviderView
|
return <ConfirmProviderView
|
||||||
provider={verifying.provider}
|
provider={verifying.provider}
|
||||||
termsChecked={alreadyCheckedTheTerms}
|
|
||||||
url={verifying.url}
|
url={verifying.url}
|
||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
setVerifying(undefined);
|
setVerifying(undefined);
|
||||||
}}
|
}}
|
||||||
onShowTerms={() => {
|
|
||||||
setReadingTerms(true)
|
|
||||||
}}
|
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
wxApi.addBackupProvider(verifying.url).then(onBack)
|
wxApi.addBackupProvider(verifying.url).then(onBack)
|
||||||
}}
|
}}
|
||||||
@ -89,50 +77,53 @@ export interface SetUrlViewProps {
|
|||||||
withError?: string;
|
withError?: string;
|
||||||
}
|
}
|
||||||
import arrowDown from '../../static/img/chevron-down.svg';
|
import arrowDown from '../../static/img/chevron-down.svg';
|
||||||
|
import { Button, ButtonPrimary, ErrorBox, Input, LightText, PopupBox, SmallTextLight } from "../components/styled/index";
|
||||||
|
import { Checkbox } from "../components/Checkbox";
|
||||||
|
|
||||||
|
function ErrorMessage({ title, description }: { title?: string, description?: string }) {
|
||||||
|
const [showErrorDetail, setShowErrorDetail] = useState(false);
|
||||||
|
if (!title) return null
|
||||||
|
return <ErrorBox>
|
||||||
|
<div>
|
||||||
|
<p>{title}</p>
|
||||||
|
<button onClick={() => { setShowErrorDetail(v => !v) }} >
|
||||||
|
<img style={{ height: '1.5em' }} src={arrowDown} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{showErrorDetail && <p>{description}</p>}
|
||||||
|
</ErrorBox>
|
||||||
|
}
|
||||||
|
|
||||||
export function SetUrlView({ initialValue, onCancel, onVerify, withError }: SetUrlViewProps) {
|
export function SetUrlView({ initialValue, onCancel, onVerify, withError }: SetUrlViewProps) {
|
||||||
const [value, setValue] = useState<string>(initialValue || "")
|
const [value, setValue] = useState<string>(initialValue || "")
|
||||||
const [error, setError] = useState<string | undefined>(withError)
|
const [error, setError] = useState<string | undefined>(withError)
|
||||||
const [showErrorDetail, setShowErrorDetail] = useState(false);
|
return <PopupBox>
|
||||||
return <div style={{ display: 'flex', flexDirection: 'column' }}>
|
<section>
|
||||||
<section style={{ height: 'calc(320px - 34px - 34px - 16px)', overflow: 'auto' }}>
|
<h1> Add backup provider</h1>
|
||||||
<div>
|
<ErrorMessage title={error && "Could not get provider information"} description={error} />
|
||||||
Add backup provider for saving coins
|
<LightText> Backup providers may charge for their service</LightText>
|
||||||
</div>
|
|
||||||
<h3>Backup provider URL</h3>
|
|
||||||
<div style={{ width: '3em', display: 'inline-block' }}>https://</div>
|
|
||||||
<input style={{ width: 'calc(100% - 8px - 4em)', marginLeft: 5 }} value={value} onChange={(e) => setValue(e.currentTarget.value)} />
|
|
||||||
<p>
|
<p>
|
||||||
Backup providers may charge for their service
|
<Input>
|
||||||
|
<label>URL</label>
|
||||||
|
<input type="text" placeholder="https://" value={value} onChange={(e) => setValue(e.currentTarget.value)} />
|
||||||
|
</Input>
|
||||||
|
<Input>
|
||||||
|
<label>Name</label>
|
||||||
|
<input type="text" disabled />
|
||||||
|
</Input>
|
||||||
</p>
|
</p>
|
||||||
{error && <Fragment>
|
|
||||||
<div class="errorbox" style={{ marginTop: 10 }} >
|
|
||||||
<div style={{ width: '100%', flexDirection: 'row', justifyContent: 'space-between', display: 'flex' }}>
|
|
||||||
<p style={{ alignSelf: 'center' }}>Could not get provider information</p>
|
|
||||||
<p>
|
|
||||||
<button style={{ fontSize: '100%', padding: 0, height: 28, width: 28 }} onClick={() => { setShowErrorDetail(v => !v) }} >
|
|
||||||
<img style={{ height: '1.5em' }} src={arrowDown} />
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{showErrorDetail && <div>{error}</div>}
|
|
||||||
</div>
|
|
||||||
</Fragment>
|
|
||||||
}
|
|
||||||
</section>
|
</section>
|
||||||
<footer style={{ marginTop: 'auto', display: 'flex', flexShrink: 0 }}>
|
<footer style={{ justifyContent: 'space-between' }}>
|
||||||
<button class="pure-button" onClick={onCancel}><i18n.Translate>cancel</i18n.Translate></button>
|
<Button onClick={onCancel}><i18n.Translate> < Back</i18n.Translate></Button>
|
||||||
<div style={{ width: '100%', flexDirection: 'row', justifyContent: 'flex-end', display: 'flex' }}>
|
<ButtonPrimary
|
||||||
<button class="pure-button button-secondary" style={{ marginLeft: 5 }}
|
disabled={!value}
|
||||||
disabled={!value}
|
onClick={() => {
|
||||||
onClick={() => {
|
let url = value.startsWith('http://') || value.startsWith('https://') ? value : `https://${value}`
|
||||||
let url = value.startsWith('http://') || value.startsWith('https://') ? value : `https://${value}`
|
url = url.endsWith('/') ? url.substring(0, url.length - 1) : url;
|
||||||
url = url.endsWith('/') ? url.substring(0, url.length - 1) : url;
|
return onVerify(url).then(r => r ? setError(r) : undefined)
|
||||||
return onVerify(url).then(r => r ? setError(r) : undefined)
|
}}><i18n.Translate>Next</i18n.Translate></ButtonPrimary>
|
||||||
}}><i18n.Translate>next</i18n.Translate></button>
|
|
||||||
</div>
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</PopupBox>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConfirmProviderViewProps {
|
export interface ConfirmProviderViewProps {
|
||||||
@ -140,34 +131,30 @@ export interface ConfirmProviderViewProps {
|
|||||||
url: string,
|
url: string,
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onConfirm: () => void;
|
onConfirm: () => void;
|
||||||
onShowTerms: () => void;
|
|
||||||
termsChecked: boolean;
|
|
||||||
}
|
}
|
||||||
export function ConfirmProviderView({ url, termsChecked, onShowTerms, provider, onCancel, onConfirm }: ConfirmProviderViewProps) {
|
export function ConfirmProviderView({ url, provider, onCancel, onConfirm }: ConfirmProviderViewProps) {
|
||||||
return <div style={{ display: 'flex', flexDirection: 'column' }}>
|
const [accepted, setAccepted] = useState(false);
|
||||||
<section style={{ height: 'calc(320px - 34px - 34px - 16px)', overflow: 'auto' }}>
|
|
||||||
<div>Verify provider service terms for <b>{url}</b> backup provider</div>
|
return <PopupBox>
|
||||||
|
<section>
|
||||||
|
<h1>Review terms of service</h1>
|
||||||
|
<div>Provider URL: <a href={url} target="_blank">{url}</a></div>
|
||||||
|
<SmallTextLight>Please review and accept this provider's terms of service</SmallTextLight>
|
||||||
|
<h2>1. Pricing</h2>
|
||||||
<p>
|
<p>
|
||||||
{Amounts.isZero(provider.annual_fee) ? 'free of charge' : provider.annual_fee} for a year of backup service
|
{Amounts.isZero(provider.annual_fee) ? 'free of charge' : `${provider.annual_fee} per year of service`}
|
||||||
</p>
|
</p>
|
||||||
|
<h2>2. Storage</h2>
|
||||||
<p>
|
<p>
|
||||||
{provider.storage_limit_in_megabytes} megabytes of storage
|
{provider.storage_limit_in_megabytes} megabytes of storage per year of service
|
||||||
</p>
|
</p>
|
||||||
|
<Checkbox label="Accept terms of service" name="terms" onToggle={() => setAccepted(old => !old)} enabled={accepted}/>
|
||||||
</section>
|
</section>
|
||||||
<footer style={{ marginTop: 'auto', display: 'flex', flexShrink: 0 }}>
|
<footer style={{ justifyContent: 'space-between' }}>
|
||||||
<button class="pure-button" onClick={onCancel}>
|
<Button onClick={onCancel}><i18n.Translate> < Back</i18n.Translate></Button>
|
||||||
<i18n.Translate>cancel</i18n.Translate>
|
<ButtonPrimary
|
||||||
</button>
|
disabled={!accepted}
|
||||||
<div style={{ width: '100%', flexDirection: 'row', justifyContent: 'flex-end', display: 'flex' }}>
|
onClick={onConfirm}><i18n.Translate>Add provider</i18n.Translate></ButtonPrimary>
|
||||||
{termsChecked ?
|
|
||||||
<button class="pure-button button-success" style={{ marginLeft: 5 }} onClick={onConfirm}>
|
|
||||||
<i18n.Translate>confirm</i18n.Translate>
|
|
||||||
</button> :
|
|
||||||
<button class="pure-button button-success" style={{ marginLeft: 5 }} onClick={onShowTerms}>
|
|
||||||
<i18n.Translate>review terms</i18n.Translate>
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</PopupBox>
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user