mirror of
https://github.com/valitydev/checkout.git
synced 2024-11-06 10:35:20 +00:00
Added copy btn for qr code (#121)
This commit is contained in:
parent
cbf893098b
commit
a6449446dc
@ -7,11 +7,19 @@ import { getActiveModalFormSelector, getLocaleSelector } from 'checkout/selector
|
|||||||
import { QRCode } from './qr-code';
|
import { QRCode } from './qr-code';
|
||||||
import { QrCodeInteractionFormInfo } from 'checkout/state';
|
import { QrCodeInteractionFormInfo } from 'checkout/state';
|
||||||
import { finishInteraction } from 'checkout/actions';
|
import { finishInteraction } from 'checkout/actions';
|
||||||
|
import { CopyToClipboardButton, Hr, Input } from 'checkout/components/ui';
|
||||||
|
|
||||||
const Instruction = styled.p`
|
const Instruction = styled.p`
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Container = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const QrCodeInteractionForm: React.FC = () => {
|
export const QrCodeInteractionForm: React.FC = () => {
|
||||||
@ -24,9 +32,12 @@ export const QrCodeInteractionForm: React.FC = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Container>
|
||||||
<Instruction>{locale['form.qr.code']}</Instruction>
|
<Instruction>{locale['form.qr.code']}</Instruction>
|
||||||
<QRCode text={request.qrCode} />
|
<QRCode text={request.qrCode} />
|
||||||
</>
|
<Hr />
|
||||||
|
<Input defaultValue={request.qrCode} readOnly={true}></Input>
|
||||||
|
<CopyToClipboardButton data={request.qrCode} />
|
||||||
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -38,13 +38,14 @@ export const Button = styled.button<{ color?: ButtonType }>`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
: css`
|
: css`
|
||||||
:hover,
|
:hover {
|
||||||
:active {
|
color: ${theme.color.primary[1.1]};
|
||||||
border-color: ${theme.color.secondary[1.1]};
|
border-color: ${theme.color.primary[1.1]};
|
||||||
}
|
}
|
||||||
|
|
||||||
:active {
|
:active {
|
||||||
color: ${theme.color.secondary[1.1]};
|
color: ${theme.color.primary[1.2]};
|
||||||
|
border-color: ${theme.color.primary[1.2]};
|
||||||
}
|
}
|
||||||
`};
|
`};
|
||||||
`;
|
`;
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import { useAppSelector } from 'checkout/configure-store';
|
||||||
|
import { getLocaleSelector } from 'checkout/selectors';
|
||||||
|
import { Button } from '../button';
|
||||||
|
|
||||||
|
export const CopyToClipboardButton: React.FC<{ data: string; timeout?: number }> = ({ data, timeout = 3000 }) => {
|
||||||
|
const locale = useAppSelector(getLocaleSelector);
|
||||||
|
const [label, setLabel] = useState(locale['form.button.copy.label']);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
setLabel(locale['form.button.copy.label']);
|
||||||
|
}, timeout);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [label]);
|
||||||
|
|
||||||
|
const copyToClipboard = (qrCode: string) => {
|
||||||
|
navigator.clipboard.writeText(qrCode);
|
||||||
|
setLabel(locale['form.button.copied.label']);
|
||||||
|
};
|
||||||
|
|
||||||
|
return <Button onClick={() => copyToClipboard(data)}>{label}</Button>;
|
||||||
|
};
|
1
src/app/components/ui/copy-to-clipboard-button/index.ts
Normal file
1
src/app/components/ui/copy-to-clipboard-button/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './copy-to-clipboard-button';
|
7
src/app/components/ui/hr/hr.tsx
Normal file
7
src/app/components/ui/hr/hr.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import styled from 'checkout/styled-components';
|
||||||
|
|
||||||
|
export const Hr = styled.hr`
|
||||||
|
width: 100%;
|
||||||
|
border: 0;
|
||||||
|
border-top: 1px solid ${({ theme }) => theme.color.neutral[0.1]};
|
||||||
|
`;
|
1
src/app/components/ui/hr/index.ts
Normal file
1
src/app/components/ui/hr/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './hr';
|
@ -8,3 +8,5 @@ export * from './input';
|
|||||||
export * from './button';
|
export * from './button';
|
||||||
export * from './metadata';
|
export * from './metadata';
|
||||||
export * from './payment-method';
|
export * from './payment-method';
|
||||||
|
export * from './hr';
|
||||||
|
export * from './copy-to-clipboard-button';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { put, call, CallEffect, PutEffect } from 'redux-saga/effects';
|
import { put, PutEffect } from 'redux-saga/effects';
|
||||||
import { InvoiceEvent, InvoiceChangeType } from 'checkout/backend';
|
import { InvoiceEvent, InvoiceChangeType } from 'checkout/backend';
|
||||||
import { Direction, GoToFormInfo, TypeKeys, SetModalState } from 'checkout/actions';
|
import { Direction, GoToFormInfo, TypeKeys, SetModalState } from 'checkout/actions';
|
||||||
import { ResultFormInfo, ResultType } from 'checkout/state';
|
import { ResultFormInfo, ResultType } from 'checkout/state';
|
||||||
@ -7,7 +7,7 @@ import { getLastChange } from 'checkout/utils';
|
|||||||
|
|
||||||
type SetStateFromEvents = GoToFormInfo | SetModalState;
|
type SetStateFromEvents = GoToFormInfo | SetModalState;
|
||||||
|
|
||||||
function* toPayload(events: InvoiceEvent[]): IterableIterator<CallEffect | SetStateFromEvents> {
|
function toPayload(events: InvoiceEvent[]): SetStateFromEvents {
|
||||||
const change = getLastChange(events);
|
const change = getLastChange(events);
|
||||||
switch (change.changeType) {
|
switch (change.changeType) {
|
||||||
case InvoiceChangeType.PaymentStatusChanged:
|
case InvoiceChangeType.PaymentStatusChanged:
|
||||||
@ -22,16 +22,13 @@ function* toPayload(events: InvoiceEvent[]): IterableIterator<CallEffect | SetSt
|
|||||||
case InvoiceChangeType.PaymentInteractionRequested:
|
case InvoiceChangeType.PaymentInteractionRequested:
|
||||||
return {
|
return {
|
||||||
type: TypeKeys.SET_MODAL_STATE,
|
type: TypeKeys.SET_MODAL_STATE,
|
||||||
payload: yield call(provideInteraction, events)
|
payload: provideInteraction(events)
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
throw { code: 'error.unsupported.invoice.change.type' };
|
throw { code: 'error.unsupported.invoice.change.type' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* provideFromInvoiceEvent(
|
export function* provideFromInvoiceEvent(events: InvoiceEvent[]): IterableIterator<PutEffect<SetStateFromEvents>> {
|
||||||
events: InvoiceEvent[]
|
return yield put<SetStateFromEvents>(toPayload(events));
|
||||||
): IterableIterator<CallEffect | PutEffect<SetStateFromEvents>> {
|
|
||||||
const payload = yield call(toPayload, events);
|
|
||||||
return yield put<SetStateFromEvents>(payload);
|
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ import {
|
|||||||
QrCodeDisplayRequest,
|
QrCodeDisplayRequest,
|
||||||
Redirect
|
Redirect
|
||||||
} from 'checkout/backend';
|
} from 'checkout/backend';
|
||||||
import { SelectEffect } from 'redux-saga/effects';
|
|
||||||
import last from 'lodash-es/last';
|
import last from 'lodash-es/last';
|
||||||
import { findChange } from 'checkout/utils';
|
import { findChange } from 'checkout/utils';
|
||||||
|
|
||||||
@ -71,9 +70,7 @@ const provideQrCode = (userInteraction: QrCodeDisplayRequest): ModalForms => {
|
|||||||
return new ModalForms([formInfo], true);
|
return new ModalForms([formInfo], true);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function* provideInteraction(
|
export function provideInteraction(events: InvoiceEvent[]): ModalState {
|
||||||
events: InvoiceEvent[]
|
|
||||||
): IterableIterator<ModalForms | ModalInteraction | SelectEffect> {
|
|
||||||
const lastEvent = last(events);
|
const lastEvent = last(events);
|
||||||
const change = last(lastEvent.changes);
|
const change = last(lastEvent.changes);
|
||||||
if (change.changeType !== InvoiceChangeType.PaymentInteractionRequested) {
|
if (change.changeType !== InvoiceChangeType.PaymentInteractionRequested) {
|
||||||
|
@ -39,6 +39,8 @@
|
|||||||
"form.button.use.other.default.label": "Use different details",
|
"form.button.use.other.default.label": "Use different details",
|
||||||
"form.button.pay.again.label": "Try again",
|
"form.button.pay.again.label": "Try again",
|
||||||
"form.button.pay.label": "Pay",
|
"form.button.pay.label": "Pay",
|
||||||
|
"form.button.copy.label": "Copy",
|
||||||
|
"form.button.copied.label": "Copied!",
|
||||||
"form.payment.method.name.card.label": "Card",
|
"form.payment.method.name.card.label": "Card",
|
||||||
"form.payment.method.name.apple.pay.label": "Apple Pay",
|
"form.payment.method.name.apple.pay.label": "Apple Pay",
|
||||||
"form.payment.method.name.google.pay.label": "Google Pay",
|
"form.payment.method.name.google.pay.label": "Google Pay",
|
||||||
|
@ -39,6 +39,8 @@
|
|||||||
"form.button.use.other.default.label": "他の詳細情報を使う",
|
"form.button.use.other.default.label": "他の詳細情報を使う",
|
||||||
"form.button.pay.again.label": "もう一度お試しください",
|
"form.button.pay.again.label": "もう一度お試しください",
|
||||||
"form.button.pay.label": "支払う",
|
"form.button.pay.label": "支払う",
|
||||||
|
"form.button.copy.label": "Copy",
|
||||||
|
"form.button.copied.label": "Copied!",
|
||||||
"form.payment.method.name.card.label": "カード",
|
"form.payment.method.name.card.label": "カード",
|
||||||
"form.payment.method.name.apple.pay.label": "Apple Pay",
|
"form.payment.method.name.apple.pay.label": "Apple Pay",
|
||||||
"form.payment.method.name.google.pay.label": "Google Pay",
|
"form.payment.method.name.google.pay.label": "Google Pay",
|
||||||
|
@ -39,6 +39,8 @@
|
|||||||
"form.button.use.other.default.label": "Use dados diferentes",
|
"form.button.use.other.default.label": "Use dados diferentes",
|
||||||
"form.button.pay.again.label": "Tente de novo",
|
"form.button.pay.again.label": "Tente de novo",
|
||||||
"form.button.pay.label": "Pagar",
|
"form.button.pay.label": "Pagar",
|
||||||
|
"form.button.copy.label": "Copiar",
|
||||||
|
"form.button.copied.label": "Сopiado!",
|
||||||
"form.payment.method.name.card.label": "Card",
|
"form.payment.method.name.card.label": "Card",
|
||||||
"form.payment.method.name.apple.pay.label": "Apple Pay",
|
"form.payment.method.name.apple.pay.label": "Apple Pay",
|
||||||
"form.payment.method.name.google.pay.label": "Google Pay",
|
"form.payment.method.name.google.pay.label": "Google Pay",
|
||||||
|
@ -39,6 +39,8 @@
|
|||||||
"form.button.use.other.default.label": "Попробовать с другими данными",
|
"form.button.use.other.default.label": "Попробовать с другими данными",
|
||||||
"form.button.pay.again.label": "Попробовать ещё раз",
|
"form.button.pay.again.label": "Попробовать ещё раз",
|
||||||
"form.button.pay.label": "Оплатить",
|
"form.button.pay.label": "Оплатить",
|
||||||
|
"form.button.copy.label": "Скопировать",
|
||||||
|
"form.button.copied.label": "Скопировано!",
|
||||||
"form.payment.method.name.card.label": "Банковская карта",
|
"form.payment.method.name.card.label": "Банковская карта",
|
||||||
"form.payment.method.name.apple.pay.label": "Apple Pay",
|
"form.payment.method.name.apple.pay.label": "Apple Pay",
|
||||||
"form.payment.method.name.google.pay.label": "Google Pay",
|
"form.payment.method.name.google.pay.label": "Google Pay",
|
||||||
|
Loading…
Reference in New Issue
Block a user