summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar <oskar@mullvad.net>2025-08-26 16:38:21 +0200
committerOskar <oskar@mullvad.net>2025-08-27 10:15:51 +0200
commit108abecc786c293a264dcd114363df3940cba76d (patch)
tree37ebd305eea70f1cddb454d2769804ee8b2f0728
parentc4d8b0cd3e69231398062c54230aa8035b577c17 (diff)
downloadmullvadvpn-108abecc786c293a264dcd114363df3940cba76d.tar.xz
mullvadvpn-108abecc786c293a264dcd114363df3940cba76d.zip
Add warning about voucher input looks like account number
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucher.tsx36
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucherStyles.tsx5
2 files changed, 36 insertions, 5 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucher.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucher.tsx
index 9f875f9c04..f9e6fd3e7a 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucher.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucher.tsx
@@ -5,12 +5,14 @@ import { formatDate } from '../../shared/account-expiry';
import { VoucherResponse } from '../../shared/daemon-rpc-types';
import { formatRelativeDate } from '../../shared/date-helper';
import { messages } from '../../shared/gettext';
+import { isAccountNumber } from '../../shared/utils';
import { useAppContext } from '../context';
import { Button, ButtonProps, Flex, Spinner } from '../lib/components';
import { IconBadge } from '../lib/icon-badge';
import { useSelector } from '../redux/store';
import { ModalAlert } from './Modal';
import {
+ StyledAccountNumberInfo,
StyledEmptyResponse,
StyledErrorResponse,
StyledInput,
@@ -26,6 +28,7 @@ interface IRedeemVoucherContextValue {
value: string;
setValue: (value: string) => void;
valueValid: boolean;
+ submittedValue: string;
submitting: boolean;
response?: VoucherResponse;
}
@@ -45,6 +48,9 @@ const RedeemVoucherContext = React.createContext<IRedeemVoucherContextValue>({
get valueValid(): boolean {
throw contextProviderMissingError;
},
+ get submittedValue(): string {
+ throw contextProviderMissingError;
+ },
get submitting(): boolean {
throw contextProviderMissingError;
},
@@ -66,6 +72,7 @@ export function RedeemVoucherContainer(props: IRedeemVoucherProps) {
const { submitVoucher } = useAppContext();
const [value, setValue] = useState('');
+ const [submittedValue, setSubmittedValue] = useState('');
const [submitting, setSubmitting] = useState(false);
const [response, setResponse] = useState<VoucherResponse>();
@@ -78,6 +85,7 @@ export function RedeemVoucherContainer(props: IRedeemVoucherProps) {
const submitTimestamp = Date.now();
setSubmitting(true);
+ setSubmittedValue(value);
onSubmit?.();
const response = await submitVoucher(value);
@@ -98,7 +106,15 @@ export function RedeemVoucherContainer(props: IRedeemVoucherProps) {
return (
<RedeemVoucherContext.Provider
- value={{ onSubmit: onSubmitWrapper, value, setValue, valueValid, submitting, response }}>
+ value={{
+ onSubmit: onSubmitWrapper,
+ value,
+ setValue,
+ valueValid,
+ submittedValue,
+ submitting,
+ response,
+ }}>
{props.children}
</RedeemVoucherContext.Provider>
);
@@ -147,7 +163,7 @@ export function RedeemVoucherInput(props: IRedeemVoucherInputProps) {
}
export function RedeemVoucherResponse() {
- const { response, submitting } = useContext(RedeemVoucherContext);
+ const { response, submitting, submittedValue } = useContext(RedeemVoucherContext);
if (submitting) {
return (
@@ -166,9 +182,19 @@ export function RedeemVoucherResponse() {
return <StyledEmptyResponse />;
case 'invalid':
return (
- <StyledErrorResponse>
- {messages.pgettext('redeem-voucher-view', 'Voucher code is invalid.')}
- </StyledErrorResponse>
+ <>
+ <StyledErrorResponse>
+ {messages.pgettext('redeem-voucher-view', 'Voucher code is invalid.')}
+ </StyledErrorResponse>
+ {isAccountNumber(submittedValue) ? (
+ <StyledAccountNumberInfo>
+ {messages.pgettext(
+ 'redeem-voucher-view',
+ 'It looks like you’ve entered an account number instead of a voucher code. If you would like to change the active account, please log out first.',
+ )}
+ </StyledAccountNumberInfo>
+ ) : null}
+ </>
);
case 'already_used':
return (
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucherStyles.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucherStyles.tsx
index b6235a3c7f..aee804c69a 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucherStyles.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucherStyles.tsx
@@ -1,5 +1,6 @@
import styled from 'styled-components';
+import { LabelTiny } from '../lib/components';
import { colors } from '../lib/foundations';
import { normalText, smallText, tinyText } from './common-styles';
import FormattableTextInput from './FormattableTextInput';
@@ -49,3 +50,7 @@ export const StyledTitle = styled.span(smallText, {
color: colors.white,
marginBottom: '5px',
});
+
+export const StyledAccountNumberInfo = styled(LabelTiny)({
+ marginTop: '8px',
+});