on master help sign in
feat: insert ticket dashes for formatting patq
bd2be65Matt Condon (shrugs)
src/form/Inputs.js+9−2
@@ -7,6 +7,7 @@ import {
7 convertToNumber,
7 convertToNumber,
8 buildFormatter,
8 buildFormatter,
9 downcase,
9 downcase,
10+ ensurePatQDashes,
10} from 'form/formatters';
11} from 'form/formatters';
11import { DEFAULT_HD_PATH } from 'lib/wallet';
12import { DEFAULT_HD_PATH } from 'lib/wallet';
12import InputSigil from 'components/InputSigil';
13import InputSigil from 'components/InputSigil';
@@ -21,7 +22,12 @@ const PLACEHOLDER_PRIVATE_KEY =
21 '0x12345abcdee6beb2f323fab48b432925c9785808d33a6ca6d7ba00b45e9370c3';
22 '0x12345abcdee6beb2f323fab48b432925c9785808d33a6ca6d7ba00b45e9370c3';
22const PLACEHOLDER_EMAIL = 'Email Address';
23const PLACEHOLDER_EMAIL = 'Email Address';
23
24
25+const TICKET_MAX_BYTE_LEN = 32; // tickets can be as large as 32 bytes
24−const formatPat = buildFormatter([downcase, prependSig]);
26+const formatPat = buildFormatter([
27+ downcase,
28+ prependSig,
29+ ensurePatQDashes(TICKET_MAX_BYTE_LEN),
30+]);
25
31
26export function TicketInput({ name, ...rest }) {
32export function TicketInput({ name, ...rest }) {
27 const {
33 const {
@@ -38,8 +44,9 @@ export function TicketInput({ name, ...rest }) {
38
44
39 return (
45 return (
40 <Input
46 <Input
41− type="password"
47+ type="text"
42 name={name}
48 name={name}
49+ obscure={value => value.replace(/[^~-]+/g, '••••••')}
43 placeholder={PLACEHOLDER_TICKET}
50 placeholder={PLACEHOLDER_TICKET}
44 autoCapitalize="none"
51 autoCapitalize="none"
45 autoCorrect="off"
52 autoCorrect="off"
src/form/formatters.js+32−2
@@ -1,6 +1,7 @@
1−import { compose } from 'lib/lib';
1+import { compose, strSplice } from 'lib/lib';
2
2
3−export const buildFormatter = (formatters = []) => compose(...formatters);
3+export const buildFormatter = (formatters = []) =>
4+ compose(...formatters.reverse());
4
5
5export const prependSig = s => {
6export const prependSig = s => {
6 if (!s || s.length === 0) {
7 if (!s || s.length === 0) {
@@ -10,6 +11,35 @@ export const prependSig = s => {
10 return s.charAt(0) === '~' ? s : `~${s}`;
11 return s.charAt(0) === '~' ? s : `~${s}`;
11};
12};
12
13
14+/**
15+ * inserts a - every 7 characters
16+ * (must be preceeded by prependSig to work correctly)
17+ * @param {number} maxByteLength the maximum number of patq blocks to have in a string
18+ */
19+export const ensurePatQDashes = maxByteLength => s => {
20+ if (!s || s.length === 0) {
21+ return s || '';
22+ }
23+
24+ // ensure there's a dash every 6 + 1 characters
25+ const dashAt = i => i * (6 + 1);
26+ const maxBlocks = maxByteLength / 2;
27+
28+ for (let i = 1; i !== maxBlocks; i++) {
29+ const dashIndex = dashAt(i);
30+
31+ if (s.length - 1 < dashIndex) {
32+ return s;
33+ }
34+
35+ if (s.charAt(dashIndex) !== '-') {
36+ s = strSplice(s, dashIndex, '-');
37+ }
38+ }
39+
40+ return s;
41+};
42+
13export const convertToNumber = s => {
43export const convertToNumber = s => {
14 try {
44 try {
15 return parseInt(s, 10);
45 return parseInt(s, 10);
src/indigo-react/components/Input.js+7−2
@@ -1,7 +1,6 @@
1import React from 'react';
1import React from 'react';
2import cn from 'classnames';
2import cn from 'classnames';
3import { useField } from 'react-final-form';
3import { useField } from 'react-final-form';
4−
5import Flex from './Flex';
4import Flex from './Flex';
6import { ErrorText } from './Typography';
5import { ErrorText } from './Typography';
7
6
@@ -15,6 +14,7 @@ export default function Input({
15 disabled = false,
14 disabled = false,
16 mono = false,
15 mono = false,
17 warning,
16 warning,
17+ obscure,
18
18
19 // callbacks
19 // callbacks
20 onEnter,
20 onEnter,
@@ -32,6 +32,9 @@ export default function Input({
32
32
33 disabled = disabled || submitting;
33 disabled = disabled || submitting;
34
34
35+ // choose the base dom component
36+ const BaseComponent = type === 'textarea' ? 'textarea' : 'input';
37+
35 // notify parent of enter keypress iff not disabled and passing
38 // notify parent of enter keypress iff not disabled and passing
36 // TODO: integrate this into react-final-form submission
39 // TODO: integrate this into react-final-form submission
37 // const onKeyPress = useCallback(
40 // const onKeyPress = useCallback(
@@ -39,6 +42,8 @@ export default function Input({
39 // [disabled, valid] // eslint-disable-line react-hooks/exhaustive-deps
42 // [disabled, valid] // eslint-disable-line react-hooks/exhaustive-deps
40 // );
43 // );
41
44
45+ // console.log(input);
46+
42 return (
47 return (
43 <Flex
48 <Flex
44 col
49 col
@@ -61,7 +66,7 @@ export default function Input({
61 <Flex.Item as={Flex} row className="rel">
66 <Flex.Item as={Flex} row className="rel">
62 <Flex.Item
67 <Flex.Item
63 flex
68 flex
64− as={type === 'textarea' ? 'textarea' : 'input'}
69+ as={BaseComponent}
65 {...rest}
70 {...rest}
66 // NOTE: 24px = 12px * 2 (from p3 styling)
71 // NOTE: 24px = 12px * 2 (from p3 styling)
67 style={type === 'textarea' ? { minHeight: 'calc(1rem + 24px)' } : {}}
72 style={type === 'textarea' ? { minHeight: 'calc(1rem + 24px)' } : {}}
src/lib/lib.js+3
@@ -16,6 +16,8 @@ const seq = n => Array.from(Array(n), (_, i) => i);
16
16
17const fill = (n, v) => Array.from(Array(n), () => v);
17const fill = (n, v) => Array.from(Array(n), () => v);
18
18
19+const strSplice = (arr, i, val) => `${arr.slice(0, i)}${val}${arr.slice(i)}`;
20+
19const isValidGalaxy = name => {
21const isValidGalaxy = name => {
20 let point;
22 let point;
21 try {
23 try {
@@ -48,6 +50,7 @@ export {
48 defaultTo,
50 defaultTo,
49 seq,
51 seq,
50 fill,
52 fill,
53+ strSplice,
51 isValidGalaxy,
54 isValidGalaxy,
52 randomPatq,
55 randomPatq,
53 patpStringLength,
56 patpStringLength,