mitre-form-component 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +1084 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1052 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +6 -2
- package/eslint.config.js +0 -28
- package/index.html +0 -13
- package/src/App.tsx +0 -33
- package/src/components/Alert/index.tsx +0 -59
- package/src/components/Alert/styles.ts +0 -95
- package/src/components/Button/index.tsx +0 -51
- package/src/components/Button/styles.ts +0 -147
- package/src/components/Form/index.tsx +0 -215
- package/src/components/Form/styles.ts +0 -99
- package/src/components/Input/index.tsx +0 -132
- package/src/components/Input/masks.ts +0 -52
- package/src/components/Input/styles.ts +0 -201
- package/src/components/hooks/useError.ts +0 -15
- package/src/components/styles/global.ts +0 -165
- package/src/components/styles/utils.ts +0 -56
- package/src/index.ts +0 -4
- package/src/main.tsx +0 -12
- package/src/registry.tsx +0 -14
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.build.json +0 -29
- package/tsconfig.json +0 -22
- package/tsup.config.ts +0 -28
- package/vite.config.ts +0 -7
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import React, { useState } from "react";
|
|
4
|
-
import { useError } from "../hooks/useError";
|
|
5
|
-
import { useForm, SubmitHandler } from "react-hook-form";
|
|
6
|
-
import { yupResolver } from "@hookform/resolvers/yup";
|
|
7
|
-
import * as yup from "yup";
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
FormContainer,
|
|
11
|
-
HeaderContainer,
|
|
12
|
-
ButtonContainer,
|
|
13
|
-
Form,
|
|
14
|
-
Title,
|
|
15
|
-
Text
|
|
16
|
-
} from "./styles";
|
|
17
|
-
import FontLoader, { GlobalStyles } from "../styles/global";
|
|
18
|
-
|
|
19
|
-
import { Input } from "../Input";
|
|
20
|
-
import { Button } from "../Button";
|
|
21
|
-
import { Alert } from "../Alert";
|
|
22
|
-
|
|
23
|
-
export interface MitreFormComponentProps {
|
|
24
|
-
productId: string;
|
|
25
|
-
apiUrl: string;
|
|
26
|
-
apiToken: string;
|
|
27
|
-
utm_source: string;
|
|
28
|
-
utm_medium: string;
|
|
29
|
-
utm_campaign: string;
|
|
30
|
-
utm_term: string;
|
|
31
|
-
showHeader?: boolean;
|
|
32
|
-
colorPrimary?: string;
|
|
33
|
-
textColor?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const schema = yup.object().shape({
|
|
37
|
-
name: yup.string().required("Nome é obrigatório"),
|
|
38
|
-
email: yup.string().required("Email é obrigatório").email("Email inválido"),
|
|
39
|
-
phone: yup.string().required("Telefone é obrigatório")
|
|
40
|
-
.test(
|
|
41
|
-
'min-digits',
|
|
42
|
-
'Número de telefone inválido!',
|
|
43
|
-
(value) => {
|
|
44
|
-
const digitsOnly = value?.replace(/\D/g, '') || '';
|
|
45
|
-
//TODO melhorar essa lógica com algum regex
|
|
46
|
-
return digitsOnly.length >= 8
|
|
47
|
-
})
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
const MitreFormComponent = React.forwardRef<HTMLDivElement, MitreFormComponentProps>(({
|
|
51
|
-
productId,
|
|
52
|
-
apiUrl,
|
|
53
|
-
apiToken,
|
|
54
|
-
utm_source,
|
|
55
|
-
utm_medium,
|
|
56
|
-
utm_campaign,
|
|
57
|
-
utm_term,
|
|
58
|
-
showHeader = true,
|
|
59
|
-
colorPrimary = "#F6C76B",
|
|
60
|
-
textColor = "#2F2F2F",
|
|
61
|
-
}, ref) => {
|
|
62
|
-
const [loading, setIsLoading] = useState(false);
|
|
63
|
-
const { error, handleError, clearError } = useError();
|
|
64
|
-
const [successMessage, setSuccessMessage] = useState('');
|
|
65
|
-
|
|
66
|
-
const { register, handleSubmit, formState: { errors }, reset, watch } = useForm({
|
|
67
|
-
resolver: yupResolver(schema),
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
const phoneValue = watch("phone");
|
|
71
|
-
|
|
72
|
-
const sendMessage: SubmitHandler<{ name: string; email: string; phone: string; }> = async (data) => {
|
|
73
|
-
const { name, email, phone } = data;
|
|
74
|
-
const message = "Gostaria de mais informações sobre o produto";
|
|
75
|
-
|
|
76
|
-
try {
|
|
77
|
-
setIsLoading(true);
|
|
78
|
-
|
|
79
|
-
if (!productId || !utm_source || !utm_medium || !utm_campaign || !utm_term || !apiToken) {
|
|
80
|
-
throw new Error("Parâmetros obrigatórios não informados");
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const response = await fetch(`${apiUrl}/leads`, {
|
|
84
|
-
method: "POST",
|
|
85
|
-
headers: {
|
|
86
|
-
"Content-Type": "application/json",
|
|
87
|
-
Authorization: `Basic ${apiToken}`,
|
|
88
|
-
},
|
|
89
|
-
body: JSON.stringify({
|
|
90
|
-
name,
|
|
91
|
-
email,
|
|
92
|
-
phone,
|
|
93
|
-
message,
|
|
94
|
-
productId,
|
|
95
|
-
utm_source,
|
|
96
|
-
utm_medium,
|
|
97
|
-
utm_campaign,
|
|
98
|
-
utm_term,
|
|
99
|
-
}),
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
if (!response.ok) {
|
|
103
|
-
throw new Error("Falha ao enviar a mensagem!");
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
setSuccessMessage("Mensagem enviada com sucesso!");
|
|
107
|
-
reset();
|
|
108
|
-
} catch (err) {
|
|
109
|
-
handleError(err);
|
|
110
|
-
} finally {
|
|
111
|
-
setIsLoading(false);
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
return (
|
|
116
|
-
<>
|
|
117
|
-
<FontLoader />
|
|
118
|
-
<GlobalStyles />
|
|
119
|
-
|
|
120
|
-
{error && (
|
|
121
|
-
<Alert
|
|
122
|
-
type="error"
|
|
123
|
-
dismissible
|
|
124
|
-
onDismiss={clearError}
|
|
125
|
-
autoDismiss={5000}
|
|
126
|
-
>
|
|
127
|
-
{error!.message}
|
|
128
|
-
</Alert>
|
|
129
|
-
)}
|
|
130
|
-
|
|
131
|
-
{successMessage && (
|
|
132
|
-
<Alert
|
|
133
|
-
type="success"
|
|
134
|
-
dismissible
|
|
135
|
-
onDismiss={() => setSuccessMessage('')}
|
|
136
|
-
autoDismiss={5000}
|
|
137
|
-
>
|
|
138
|
-
{successMessage}
|
|
139
|
-
</Alert>
|
|
140
|
-
)}
|
|
141
|
-
|
|
142
|
-
<FormContainer ref={ref} >
|
|
143
|
-
{showHeader &&
|
|
144
|
-
<HeaderContainer>
|
|
145
|
-
<Title $textColor={textColor}>Atendimento por mensagem</Title>
|
|
146
|
-
|
|
147
|
-
<Text $textColor={textColor}>Informe seus dados e retornaremos a mensagem.</Text>
|
|
148
|
-
</HeaderContainer>
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
<Form $textColor={textColor} onSubmit={handleSubmit(sendMessage)} noValidate>
|
|
152
|
-
<Input
|
|
153
|
-
id="name"
|
|
154
|
-
label="Nome *"
|
|
155
|
-
placeholder="Digite seu nome"
|
|
156
|
-
{...register("name")}
|
|
157
|
-
borderColor={colorPrimary}
|
|
158
|
-
textColor={textColor}
|
|
159
|
-
error={errors.name?.message}
|
|
160
|
-
autoComplete="name"
|
|
161
|
-
required
|
|
162
|
-
/>
|
|
163
|
-
|
|
164
|
-
<Input
|
|
165
|
-
id="email"
|
|
166
|
-
label="Email *"
|
|
167
|
-
type="email"
|
|
168
|
-
placeholder="exemplo@email.com"
|
|
169
|
-
{...register("email")}
|
|
170
|
-
borderColor={colorPrimary}
|
|
171
|
-
textColor={textColor}
|
|
172
|
-
error={errors.email?.message}
|
|
173
|
-
autoComplete="email"
|
|
174
|
-
required
|
|
175
|
-
/>
|
|
176
|
-
|
|
177
|
-
<Input
|
|
178
|
-
id="phone"
|
|
179
|
-
label="Telefone *"
|
|
180
|
-
placeholder="(11) 00000-0000"
|
|
181
|
-
mask="phone"
|
|
182
|
-
{...register("phone")}
|
|
183
|
-
borderColor={colorPrimary}
|
|
184
|
-
textColor={textColor}
|
|
185
|
-
error={errors.phone?.message}
|
|
186
|
-
required
|
|
187
|
-
value={phoneValue}
|
|
188
|
-
/>
|
|
189
|
-
|
|
190
|
-
<h6>* Campos de preenchimento obrigatório.</h6>
|
|
191
|
-
|
|
192
|
-
<ButtonContainer>
|
|
193
|
-
<Button bgColor={colorPrimary} color={textColor} type="submit" isSubmitting={loading}>
|
|
194
|
-
Enviar mensagem
|
|
195
|
-
</Button>
|
|
196
|
-
</ButtonContainer>
|
|
197
|
-
|
|
198
|
-
<p>A Mitre Realty respeita a sua privacidade e utiliza os seus dados pessoais para contatá-lo por e-mail ou telefone aqui registrados. Para saber mais, acesse a nossa{ ' '}
|
|
199
|
-
<a
|
|
200
|
-
href="https://www.mitrerealty.com.br/politica-de-privacidade"
|
|
201
|
-
target="_blank"
|
|
202
|
-
rel="noopener noreferrer"
|
|
203
|
-
>
|
|
204
|
-
Política de Privacidade
|
|
205
|
-
</a>. Ao clicar em {'"'}enviar{'"'}, você concorda em permitir que a Mitre Realty, armazene e processe os dados pessoais fornecidos por você para finalidade informada</p>
|
|
206
|
-
|
|
207
|
-
</Form>
|
|
208
|
-
</FormContainer>
|
|
209
|
-
</>
|
|
210
|
-
);
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
MitreFormComponent.displayName = "MitreFormComponent";
|
|
214
|
-
|
|
215
|
-
export default MitreFormComponent;
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { flex, opacityEffect } from "../styles/utils";
|
|
2
|
-
import styled from "styled-components";
|
|
3
|
-
|
|
4
|
-
export const FormContainer = styled.div`
|
|
5
|
-
${flex("column")}
|
|
6
|
-
align-items: stretch;
|
|
7
|
-
justify-content: flex-start;
|
|
8
|
-
overflow-x: hidden;
|
|
9
|
-
overflow-y: auto;
|
|
10
|
-
|
|
11
|
-
/* Hide scrollbars for WebKit browsers */
|
|
12
|
-
::-webkit-scrollbar {
|
|
13
|
-
display: none;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/* Hide scrollbars for Firefox */
|
|
17
|
-
scrollbar-width: none;
|
|
18
|
-
|
|
19
|
-
box-sizing: border-box;
|
|
20
|
-
`;
|
|
21
|
-
|
|
22
|
-
export const HeaderContainer = styled.div`
|
|
23
|
-
margin-bottom: 1rem;
|
|
24
|
-
`;
|
|
25
|
-
|
|
26
|
-
export const ButtonContainer = styled.div`
|
|
27
|
-
display: flex;
|
|
28
|
-
flex-direction: column;
|
|
29
|
-
align-items: center;
|
|
30
|
-
justify-content: center;
|
|
31
|
-
width: 100%;
|
|
32
|
-
margin-top: 0.75rem;
|
|
33
|
-
`;
|
|
34
|
-
|
|
35
|
-
export const Form = styled.form<{ $textColor: string }>`
|
|
36
|
-
label {
|
|
37
|
-
font-weight: 700;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
input {
|
|
41
|
-
background: white;
|
|
42
|
-
margin-bottom: 0.75rem;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
p {
|
|
46
|
-
font-family: "Montserrat", sans-serif;
|
|
47
|
-
font-style: italic;
|
|
48
|
-
font-weight: 200;
|
|
49
|
-
font-size: 0.8rem;
|
|
50
|
-
color: ${(props) => props.$textColor || "var(--black)"};
|
|
51
|
-
text-align: start;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
a {
|
|
55
|
-
font-family: "Montserrat", sans-serif;
|
|
56
|
-
font-style: italic;
|
|
57
|
-
font-weight: 200;
|
|
58
|
-
font-size: 0.8rem;
|
|
59
|
-
color: ${(props) => props.$textColor || "var(--black)"};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
h6 {
|
|
63
|
-
text-align: start;
|
|
64
|
-
margin-left: 10px;
|
|
65
|
-
color: ${(props) => props.$textColor || "var(--black)"};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
& > div {
|
|
69
|
-
margin-bottom: 10px;,
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
button {
|
|
73
|
-
${opacityEffect}
|
|
74
|
-
color: var(--black);
|
|
75
|
-
font-weight: 600;
|
|
76
|
-
border: none;
|
|
77
|
-
border-radius: 8px;
|
|
78
|
-
width: 60%;
|
|
79
|
-
margin-top: 10px;
|
|
80
|
-
margin-bottom: 10px;
|
|
81
|
-
}
|
|
82
|
-
`;
|
|
83
|
-
|
|
84
|
-
export const Title = styled.h2<{ $textColor: string }>`
|
|
85
|
-
font-size: 1.25rem;
|
|
86
|
-
font-weight: 700;
|
|
87
|
-
line-height: 24px;
|
|
88
|
-
letter-spacing: 0em;
|
|
89
|
-
color: ${(props) => props.$textColor || "var(--black)"};
|
|
90
|
-
`;
|
|
91
|
-
|
|
92
|
-
export const Text = styled.p<{ $textColor: string }>`
|
|
93
|
-
font-size: 1rem;
|
|
94
|
-
font-weight: 400;
|
|
95
|
-
line-height: 23px;
|
|
96
|
-
letter-spacing: 0em;
|
|
97
|
-
margin-top: 10px;
|
|
98
|
-
color: ${(props) => props.$textColor || "var(--black)"};
|
|
99
|
-
`;
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FormEvent,
|
|
3
|
-
forwardRef,
|
|
4
|
-
ForwardRefRenderFunction,
|
|
5
|
-
InputHTMLAttributes,
|
|
6
|
-
useCallback,
|
|
7
|
-
useRef,
|
|
8
|
-
} from "react";
|
|
9
|
-
import { FieldError } from "react-hook-form";
|
|
10
|
-
import { cep, cpf, currency, date } from "./masks";
|
|
11
|
-
|
|
12
|
-
import 'react-phone-input-2/lib/style.css'
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
FormControl,
|
|
16
|
-
FormErrorMessage,
|
|
17
|
-
FormLabel,
|
|
18
|
-
Input as FormInput,
|
|
19
|
-
FormPhoneInput
|
|
20
|
-
} from "./styles";
|
|
21
|
-
|
|
22
|
-
type InputType =
|
|
23
|
-
| "text"
|
|
24
|
-
| "email"
|
|
25
|
-
| "password"
|
|
26
|
-
| "number"
|
|
27
|
-
| "tel"
|
|
28
|
-
| "url"
|
|
29
|
-
| "date"
|
|
30
|
-
| "time"
|
|
31
|
-
| "datetime-local";
|
|
32
|
-
|
|
33
|
-
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
34
|
-
id: string;
|
|
35
|
-
label?: string;
|
|
36
|
-
error?: string | FieldError;
|
|
37
|
-
showErrorMessage?: boolean;
|
|
38
|
-
borderColor: string;
|
|
39
|
-
textColor?: string;
|
|
40
|
-
|
|
41
|
-
mask?: "cep" | "currency" | "cpf" | "phone" | "date";
|
|
42
|
-
type?: InputType;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const InputBase: ForwardRefRenderFunction<HTMLInputElement, InputProps> = (
|
|
46
|
-
{ id, label, error, showErrorMessage = true, borderColor, textColor, mask = "", type = "text", ...rest },
|
|
47
|
-
ref
|
|
48
|
-
) => {
|
|
49
|
-
const phoneInputRef = useRef<{ input: HTMLInputElement }>(null);
|
|
50
|
-
const { onChange, name } = rest;
|
|
51
|
-
|
|
52
|
-
const handleKeyUp = useCallback(
|
|
53
|
-
(e: FormEvent<HTMLInputElement>) => {
|
|
54
|
-
if (mask === "cep") cep(e);
|
|
55
|
-
if (mask === "currency") currency(e);
|
|
56
|
-
if (mask === "cpf") cpf(e);
|
|
57
|
-
if (mask === "date") date(e);
|
|
58
|
-
},
|
|
59
|
-
[mask]
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
const handlePhoneChange = useCallback((value: string) => {
|
|
63
|
-
onChange?.({ target: { value, name } } as React.ChangeEvent<HTMLInputElement>);
|
|
64
|
-
|
|
65
|
-
if (phoneInputRef.current?.input) {
|
|
66
|
-
phoneInputRef.current.input.value = value;
|
|
67
|
-
}
|
|
68
|
-
}, [onChange, name]);
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<FormControl isInvalid={!!error}>
|
|
72
|
-
{!!label && <FormLabel htmlFor={id} $textColor={textColor}>{label}</FormLabel>}
|
|
73
|
-
|
|
74
|
-
{!mask ? (
|
|
75
|
-
<FormInput
|
|
76
|
-
id={id}
|
|
77
|
-
ref={ref}
|
|
78
|
-
type={type}
|
|
79
|
-
$bordercolor={borderColor}
|
|
80
|
-
aria-invalid={!!error && showErrorMessage ? "true" : "false"}
|
|
81
|
-
autoComplete={rest.autoComplete || "on"}
|
|
82
|
-
{...rest}
|
|
83
|
-
/>
|
|
84
|
-
) : mask === 'phone' ? (
|
|
85
|
-
<FormPhoneInput
|
|
86
|
-
country={"br"}
|
|
87
|
-
$bordercolor={borderColor}
|
|
88
|
-
placeholder={rest.placeholder}
|
|
89
|
-
aria-invalid={!!error && showErrorMessage ? "true" : "false"}
|
|
90
|
-
isInvalid={!!error}
|
|
91
|
-
onChange={handlePhoneChange}
|
|
92
|
-
masks={{
|
|
93
|
-
br: "(..) .....-....",}}
|
|
94
|
-
inputProps={{
|
|
95
|
-
id,
|
|
96
|
-
name: 'phone',
|
|
97
|
-
required: true,
|
|
98
|
-
autoFocus: true,
|
|
99
|
-
autoComplete: "tel",
|
|
100
|
-
ref: phoneInputRef,
|
|
101
|
-
}}
|
|
102
|
-
//TODO no futuro enviar com o ddi, só retirar o disableCountryCode e disableCountryGuess
|
|
103
|
-
dropdownStyle={{
|
|
104
|
-
color: textColor,
|
|
105
|
-
}}
|
|
106
|
-
disableCountryGuess={true}
|
|
107
|
-
disableCountryCode={true}
|
|
108
|
-
value={rest.value as string}
|
|
109
|
-
/>
|
|
110
|
-
) : (
|
|
111
|
-
<FormInput
|
|
112
|
-
id={id}
|
|
113
|
-
ref={ref}
|
|
114
|
-
type={type}
|
|
115
|
-
$bordercolor={borderColor}
|
|
116
|
-
aria-invalid={!!error && showErrorMessage ? "true" : "false"}
|
|
117
|
-
onKeyUp={handleKeyUp}
|
|
118
|
-
autoComplete={rest.autoComplete || "on"}
|
|
119
|
-
{...rest}
|
|
120
|
-
/>
|
|
121
|
-
)}
|
|
122
|
-
|
|
123
|
-
{!!error && showErrorMessage && (
|
|
124
|
-
<FormErrorMessage data-testid="error-message">
|
|
125
|
-
{typeof error === 'string' ? error : error.message}
|
|
126
|
-
</FormErrorMessage>
|
|
127
|
-
)}
|
|
128
|
-
</FormControl>
|
|
129
|
-
);
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
export const Input = forwardRef(InputBase);
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { FormEvent } from "react";
|
|
2
|
-
|
|
3
|
-
export function cep(e: FormEvent<HTMLInputElement>) {
|
|
4
|
-
e.currentTarget.maxLength = 9;
|
|
5
|
-
let value = e.currentTarget.value;
|
|
6
|
-
value = value.replace(/\D/g, "");
|
|
7
|
-
value = value.replace(/^(\d{5})(\d)/, "$1-$2");
|
|
8
|
-
e.currentTarget.value = value;
|
|
9
|
-
return e;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function currency(e: FormEvent<HTMLInputElement>) {
|
|
13
|
-
let value = e.currentTarget.value;
|
|
14
|
-
value = value.replace(/\D/g, "");
|
|
15
|
-
value = value.replace(/(\d)(\d{2})$/, "$1,$2");
|
|
16
|
-
value = value.replace(/(?=(\d{3})+(\D))\B/g, ".");
|
|
17
|
-
|
|
18
|
-
e.currentTarget.value = value;
|
|
19
|
-
return e;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function cpf(e: FormEvent<HTMLInputElement>) {
|
|
23
|
-
e.currentTarget.maxLength = 14;
|
|
24
|
-
let value = e.currentTarget.value;
|
|
25
|
-
if (!value.match(/^(\d{3}).(\d{3}).(\d{3})-(\d{2})$/)) {
|
|
26
|
-
value = value.replace(/\D/g, "");
|
|
27
|
-
value = value.replace(/(\d{3})(\d)/, "$1.$2");
|
|
28
|
-
value = value.replace(/(\d{3})(\d)/, "$1.$2");
|
|
29
|
-
value = value.replace(/(\d{3})(\d{2})$/, "$1-$2");
|
|
30
|
-
|
|
31
|
-
e.currentTarget.value = value;
|
|
32
|
-
}
|
|
33
|
-
return e;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function date(e: FormEvent<HTMLInputElement>) {
|
|
37
|
-
let value = e.currentTarget.value;
|
|
38
|
-
value = value.replace(/\D/g, "");
|
|
39
|
-
value = value.replace(/(\d{2})(\d)/, "$1/$2");
|
|
40
|
-
value = value.replace(/(\d{2})(\d)/, "$1/$2");
|
|
41
|
-
e.currentTarget.value = value;
|
|
42
|
-
return e;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function phone(e: FormEvent<HTMLInputElement>) {
|
|
46
|
-
let value = e.currentTarget.value;
|
|
47
|
-
value = value.replace(/\D/g, "");
|
|
48
|
-
value = value.replace(/(\d{2})(\d)/, "$1/$2");
|
|
49
|
-
value = value.replace(/(\d{2})(\d)/, "$1/$2");
|
|
50
|
-
e.currentTarget.value = value;
|
|
51
|
-
return e;
|
|
52
|
-
}
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import styled, { css } from "styled-components";
|
|
2
|
-
import { InputHTMLAttributes } from "react";
|
|
3
|
-
|
|
4
|
-
import PhoneInput from "react-phone-input-2";
|
|
5
|
-
|
|
6
|
-
type InputProps = {
|
|
7
|
-
isInvalid?: boolean;
|
|
8
|
-
bordercolor?: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export const FormLabel = styled.label<InputProps & { $textColor?: string }>`
|
|
12
|
-
font-family: "Montserrat", sans-serif;
|
|
13
|
-
font-style: normal;
|
|
14
|
-
font-weight: 500;
|
|
15
|
-
font-size: 1rem;
|
|
16
|
-
color: ${(props) =>
|
|
17
|
-
props.isInvalid ? "var(--red)" : props.$textColor || "var(--black)"};
|
|
18
|
-
display: block;
|
|
19
|
-
margin-bottom: 0.5rem;
|
|
20
|
-
text-align: left;
|
|
21
|
-
`;
|
|
22
|
-
|
|
23
|
-
export const Input = styled.input<
|
|
24
|
-
InputHTMLAttributes<HTMLInputElement> & { $bordercolor?: string }
|
|
25
|
-
>`
|
|
26
|
-
font-family: "Montserrat", sans-serif;
|
|
27
|
-
font-style: normal;
|
|
28
|
-
font-weight: 500;
|
|
29
|
-
font-size: 1rem;
|
|
30
|
-
line-height: 1.5rem;
|
|
31
|
-
background: var(--gray-500);
|
|
32
|
-
color: var(--black);
|
|
33
|
-
padding: 0.5rem;
|
|
34
|
-
border-radius: 0.125rem;
|
|
35
|
-
border: 1px solid transparent;
|
|
36
|
-
display: block;
|
|
37
|
-
height: 3.125rem;
|
|
38
|
-
width: 100%;
|
|
39
|
-
|
|
40
|
-
&:focus {
|
|
41
|
-
border-radius: 0.125rem;
|
|
42
|
-
border: 2px solid ${(props) => props.$bordercolor || "var(--yellow-500)"};
|
|
43
|
-
outline: none;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
&::placeholder {
|
|
47
|
-
font-size: 1rem;
|
|
48
|
-
line-height: 1.5rem;
|
|
49
|
-
color: #b6b6b6;
|
|
50
|
-
font-weight: 800;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/* Autofill styles */
|
|
54
|
-
&:-webkit-autofill {
|
|
55
|
-
background: var(--gray-500) !important;
|
|
56
|
-
color: var(--black) !important;
|
|
57
|
-
-webkit-text-fill-color: var(--black) !important;
|
|
58
|
-
transition: background-color 5000s ease-in-out 0s; /* Prevent flashing */
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
&:-webkit-autofill::first-line {
|
|
62
|
-
font-family: "Montserrat", sans-serif;
|
|
63
|
-
font-size: 1rem;
|
|
64
|
-
font-weight: 500;
|
|
65
|
-
}
|
|
66
|
-
`;
|
|
67
|
-
|
|
68
|
-
export const FormPhoneInput = styled(PhoneInput)<
|
|
69
|
-
InputProps & { $bordercolor?: string; $textColor?: string }
|
|
70
|
-
>`
|
|
71
|
-
.form-control {
|
|
72
|
-
background: white;
|
|
73
|
-
color: ${(props) =>
|
|
74
|
-
props.isInvalid ? "var(--red)" : props.$textColor || "var(--black)"};
|
|
75
|
-
padding: 0.5rem;
|
|
76
|
-
border-radius: 0.125rem;
|
|
77
|
-
border: 1px solid transparent;
|
|
78
|
-
height: 3.125rem;
|
|
79
|
-
width: 100%;
|
|
80
|
-
padding-left: 4rem;
|
|
81
|
-
font-family: "Montserrat", sans-serif;
|
|
82
|
-
font-style: normal;
|
|
83
|
-
font-weight: 500;
|
|
84
|
-
font-size: 1rem;
|
|
85
|
-
line-height: 1.5rem;
|
|
86
|
-
text &:focus,
|
|
87
|
-
&:focus-within {
|
|
88
|
-
border-radius: 0.125rem;
|
|
89
|
-
border: 2px solid
|
|
90
|
-
${(props) =>
|
|
91
|
-
!props.isValid
|
|
92
|
-
? "var(--red)"
|
|
93
|
-
: props.$bordercolor || "var(--yellow-500)"};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
&::placeholder {
|
|
97
|
-
font-size: 1rem;
|
|
98
|
-
line-height: 1.5rem;
|
|
99
|
-
color: #b6b6b6;
|
|
100
|
-
font-weight: 800;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/* Autofill styles */
|
|
104
|
-
&:-webkit-autofill {
|
|
105
|
-
background: var(--gray-500) !important;
|
|
106
|
-
color: var(--black) !important;
|
|
107
|
-
-webkit-text-fill-color: var(--black) !important;
|
|
108
|
-
transition: background-color 5000s ease-in-out 0s; /* Prevent flashing */
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
&:-webkit-autofill::first-line {
|
|
112
|
-
font-family: "Montserrat", sans-serif;
|
|
113
|
-
font-size: 1rem;
|
|
114
|
-
font-weight: 500;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
&:focus-within {
|
|
119
|
-
.form-control {
|
|
120
|
-
border: 2px solid
|
|
121
|
-
${(props) =>
|
|
122
|
-
props.isInvalid
|
|
123
|
-
? "var(--red)"
|
|
124
|
-
: props.$bordercolor || "var(--yellow-500)"};
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.flag-dropdown {
|
|
129
|
-
background: white;
|
|
130
|
-
border: none;
|
|
131
|
-
padding: 0.5rem;
|
|
132
|
-
margin: 0.25rem;
|
|
133
|
-
cursor: pointer;
|
|
134
|
-
|
|
135
|
-
&:focus-within {
|
|
136
|
-
outline: none;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
`;
|
|
140
|
-
|
|
141
|
-
export const FormErrorMessage = styled.small`
|
|
142
|
-
font-size: 0.75rem;
|
|
143
|
-
line-height: 1.125rem;
|
|
144
|
-
color: var(--red);
|
|
145
|
-
margin-top: 0.25rem;
|
|
146
|
-
display: block;
|
|
147
|
-
`;
|
|
148
|
-
|
|
149
|
-
export const FormControl = styled.div.withConfig({
|
|
150
|
-
shouldForwardProp: (prop) => !["isInvalid", "$bordercolor"].includes(prop),
|
|
151
|
-
})<{ isInvalid?: boolean; $bordercolor?: string }>`
|
|
152
|
-
${FormLabel} {
|
|
153
|
-
${(props) =>
|
|
154
|
-
props.isInvalid &&
|
|
155
|
-
css`
|
|
156
|
-
color: var(--red);
|
|
157
|
-
`};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
${Input} {
|
|
161
|
-
${(props) =>
|
|
162
|
-
props.isInvalid &&
|
|
163
|
-
css`
|
|
164
|
-
border: 1px solid var(--red);
|
|
165
|
-
|
|
166
|
-
&:not(:focus)::placeholder {
|
|
167
|
-
color: var(--red);
|
|
168
|
-
font-weight: 600;
|
|
169
|
-
}
|
|
170
|
-
`};
|
|
171
|
-
|
|
172
|
-
&:focus {
|
|
173
|
-
${(props) =>
|
|
174
|
-
props.isInvalid &&
|
|
175
|
-
css`
|
|
176
|
-
border: 1px solid var(--red);
|
|
177
|
-
`};
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
${FormPhoneInput} {
|
|
182
|
-
${(props) =>
|
|
183
|
-
props.isInvalid &&
|
|
184
|
-
css`
|
|
185
|
-
border: 1px solid var(--red);
|
|
186
|
-
|
|
187
|
-
&:not(:focus)::placeholder {
|
|
188
|
-
color: var(--red);
|
|
189
|
-
font-weight: 600;
|
|
190
|
-
}
|
|
191
|
-
`};
|
|
192
|
-
|
|
193
|
-
&:focus {
|
|
194
|
-
${(props) =>
|
|
195
|
-
props.isInvalid &&
|
|
196
|
-
css`
|
|
197
|
-
border: 1px solid var(--red);
|
|
198
|
-
`};
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
`;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
2
|
-
|
|
3
|
-
export function useError() {
|
|
4
|
-
const [error, setError] = useState<Error | null>(null);
|
|
5
|
-
|
|
6
|
-
const handleError = (err: unknown) => {
|
|
7
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
8
|
-
setError(errorObj);
|
|
9
|
-
console.error(errorObj);
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const clearError = () => setError(null);
|
|
13
|
-
|
|
14
|
-
return { error, handleError, clearError };
|
|
15
|
-
}
|