Added copy btn for qr code (#121)

This commit is contained in:
Ildar Galeev 2022-07-13 18:44:37 +03:00 committed by GitHub
parent cbf893098b
commit a6449446dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 68 additions and 18 deletions

View File

@ -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>
); );
}; };

View File

@ -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]};
} }
`}; `};
`; `;

View File

@ -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>;
};

View File

@ -0,0 +1 @@
export * from './copy-to-clipboard-button';

View 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]};
`;

View File

@ -0,0 +1 @@
export * from './hr';

View File

@ -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';

View File

@ -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);
} }

View File

@ -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) {

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",