@stackshift-ui/signin-signup 6.0.3 → 6.0.4
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/package.json +16 -15
- package/src/helper/index.ts +28 -0
- package/src/index.ts +6 -0
- package/src/signin-signup.test.tsx +13 -0
- package/src/signin-signup.tsx +42 -0
- package/src/signin_signup_a.tsx +287 -0
- package/src/signin_signup_b.tsx +257 -0
- package/src/types.ts +412 -0
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackshift-ui/signin-signup",
|
|
3
3
|
"description": "",
|
|
4
|
-
"version": "6.0.
|
|
4
|
+
"version": "6.0.4",
|
|
5
5
|
"private": false,
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"module": "./dist/index.mjs",
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
10
10
|
"files": [
|
|
11
|
-
"dist/**"
|
|
11
|
+
"dist/**",
|
|
12
|
+
"src"
|
|
12
13
|
],
|
|
13
14
|
"author": "WebriQ <info@webriq.com>",
|
|
14
15
|
"devDependencies": {
|
|
@@ -33,20 +34,20 @@
|
|
|
33
34
|
},
|
|
34
35
|
"dependencies": {
|
|
35
36
|
"classnames": "^2.5.1",
|
|
37
|
+
"@stackshift-ui/card": "6.0.3",
|
|
36
38
|
"@stackshift-ui/scripts": "6.0.2",
|
|
37
|
-
"@stackshift-ui/
|
|
38
|
-
"@stackshift-ui/
|
|
39
|
-
"@stackshift-ui/
|
|
40
|
-
"@stackshift-ui/
|
|
41
|
-
"@stackshift-ui/
|
|
42
|
-
"@stackshift-ui/
|
|
43
|
-
"@stackshift-ui/
|
|
44
|
-
"@stackshift-ui/
|
|
45
|
-
"@stackshift-ui/form": "6.0.
|
|
46
|
-
"@stackshift-ui/
|
|
47
|
-
"@stackshift-ui/
|
|
48
|
-
"@stackshift-ui/
|
|
49
|
-
"@stackshift-ui/flex": "6.0.2"
|
|
39
|
+
"@stackshift-ui/heading": "6.0.3",
|
|
40
|
+
"@stackshift-ui/system": "6.0.3",
|
|
41
|
+
"@stackshift-ui/button": "6.0.3",
|
|
42
|
+
"@stackshift-ui/input": "6.0.4",
|
|
43
|
+
"@stackshift-ui/text": "6.0.3",
|
|
44
|
+
"@stackshift-ui/link": "6.0.3",
|
|
45
|
+
"@stackshift-ui/image": "6.0.3",
|
|
46
|
+
"@stackshift-ui/form": "6.0.3",
|
|
47
|
+
"@stackshift-ui/form-field": "6.0.4",
|
|
48
|
+
"@stackshift-ui/section": "6.0.3",
|
|
49
|
+
"@stackshift-ui/flex": "6.0.3",
|
|
50
|
+
"@stackshift-ui/container": "6.0.3"
|
|
50
51
|
},
|
|
51
52
|
"peerDependencies": {
|
|
52
53
|
"@types/react": "16.8 - 19",
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Logo } from "../types";
|
|
2
|
+
|
|
3
|
+
// Logo link
|
|
4
|
+
export const logoLink = (logo: Logo) => {
|
|
5
|
+
if (logo?.internalLink && logo?.type === "linkInternal") {
|
|
6
|
+
if (logo?.internalLink?.toLowerCase()?.includes("home")) {
|
|
7
|
+
return "/";
|
|
8
|
+
}
|
|
9
|
+
return `/${logo.internalLink}`;
|
|
10
|
+
} else if (logo?.externalLink && logo?.type === "linkExternal") {
|
|
11
|
+
return logo?.externalLink ?? "/";
|
|
12
|
+
} else {
|
|
13
|
+
return "/";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// WebriQ form redirect thank you page on successful submission
|
|
18
|
+
export const thankYouPageLink = (link: any) => {
|
|
19
|
+
if (!link) {
|
|
20
|
+
return "/thank-you";
|
|
21
|
+
} else {
|
|
22
|
+
if (link?.linkType === "linkInternal") {
|
|
23
|
+
return `/${link?.internalLink}`;
|
|
24
|
+
} else {
|
|
25
|
+
return link?.externalLink;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { cleanup, render, screen } from "@testing-library/react";
|
|
2
|
+
import { afterEach, describe, test } from "vitest";
|
|
3
|
+
import { SigninSignup } from "./signin-signup";
|
|
4
|
+
|
|
5
|
+
describe.concurrent("signin-signup", () => {
|
|
6
|
+
afterEach(cleanup);
|
|
7
|
+
|
|
8
|
+
test.skip("Dummy test - test if renders without errors", ({ expect }) => {
|
|
9
|
+
const clx = "my-class";
|
|
10
|
+
render(<SigninSignup />);
|
|
11
|
+
expect(screen.getByTestId("{ kebabCase name }}").classList).toContain(clx);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React, { lazy } from "react";
|
|
2
|
+
import { SectionsProps, Logo, LabeledRoute, LabeledRouteWithKey, Form } from "./types";
|
|
3
|
+
|
|
4
|
+
const Variants = {
|
|
5
|
+
variant_a: lazy(() => import("./signin_signup_a")),
|
|
6
|
+
variant_b: lazy(() => import("./signin_signup_b")),
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export interface SignUpFormProps {
|
|
10
|
+
logo?: Logo;
|
|
11
|
+
title?: string;
|
|
12
|
+
subtitle?: string;
|
|
13
|
+
text?: string;
|
|
14
|
+
firstButton?: LabeledRoute;
|
|
15
|
+
secondButton?: LabeledRoute;
|
|
16
|
+
formLinks?: LabeledRouteWithKey[];
|
|
17
|
+
signInLink?: LabeledRoute;
|
|
18
|
+
form?: Form;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const displayName = "SigninSignup";
|
|
22
|
+
|
|
23
|
+
export const SigninSignup: React.FC<SectionsProps> = ({ data }) => {
|
|
24
|
+
const variant = data?.variant;
|
|
25
|
+
const Variant = variant && Variants?.[variant as keyof typeof Variants];
|
|
26
|
+
|
|
27
|
+
const props = {
|
|
28
|
+
logo: data?.variants?.logo ?? undefined,
|
|
29
|
+
title: data?.variants?.title ?? undefined,
|
|
30
|
+
subtitle: data?.variants?.subtitle ?? undefined,
|
|
31
|
+
text: data?.variants?.plainText ?? undefined,
|
|
32
|
+
firstButton: data?.variants?.primaryButton ?? undefined,
|
|
33
|
+
secondButton: data?.variants?.secondaryButton ?? undefined,
|
|
34
|
+
formLinks: data?.variants?.formLinks ?? undefined,
|
|
35
|
+
signInLink: data?.variants?.signinLink ?? undefined,
|
|
36
|
+
form: data?.variants?.form ?? undefined,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return Variant ? <Variant {...props} /> : null;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
SigninSignup.displayName = displayName;
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { Button } from "@stackshift-ui/button";
|
|
2
|
+
import { Container } from "@stackshift-ui/container";
|
|
3
|
+
import { Flex } from "@stackshift-ui/flex";
|
|
4
|
+
import { Form } from "@stackshift-ui/form";
|
|
5
|
+
import { FormField } from "@stackshift-ui/form-field";
|
|
6
|
+
import { Heading } from "@stackshift-ui/heading";
|
|
7
|
+
import { Image } from "@stackshift-ui/image";
|
|
8
|
+
import { Input } from "@stackshift-ui/input";
|
|
9
|
+
import { Link } from "@stackshift-ui/link";
|
|
10
|
+
import { Section } from "@stackshift-ui/section";
|
|
11
|
+
import { Text } from "@stackshift-ui/text";
|
|
12
|
+
import React from "react";
|
|
13
|
+
|
|
14
|
+
import { SignUpFormProps } from ".";
|
|
15
|
+
import { logoLink, thankYouPageLink } from "./helper";
|
|
16
|
+
import { LabeledRoute, LabeledRouteWithKey, Logo, Form as iForm } from "./types";
|
|
17
|
+
|
|
18
|
+
export default function SigninSignup_A({ logo, form, formLinks, signInLink }: SignUpFormProps) {
|
|
19
|
+
return (
|
|
20
|
+
<Section className="py-10 bg-gray-50 lg:py-20">
|
|
21
|
+
<Container maxWidth={576}>
|
|
22
|
+
<LogoSection logo={logo} />
|
|
23
|
+
<Container className="mb-6 text-center lg:mb-10">
|
|
24
|
+
<SubtitleAndHeadingText form={form} />
|
|
25
|
+
<SignupForm
|
|
26
|
+
form={form}
|
|
27
|
+
signInLink={signInLink}
|
|
28
|
+
thankYouPage={thankYouPageLink(form?.thankYouPage)}
|
|
29
|
+
/>
|
|
30
|
+
</Container>
|
|
31
|
+
<FormLinks formLinks={formLinks} />
|
|
32
|
+
</Container>
|
|
33
|
+
</Section>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function LogoSection({ logo }: { logo?: Logo }) {
|
|
38
|
+
if (!logo) return null;
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div className="mb-10">
|
|
42
|
+
<Link
|
|
43
|
+
aria-label={`Go to ${logoLink(logo) === "/" ? "home page" : logoLink(logo)}`}
|
|
44
|
+
className="flex justify-center mx-auto text-3xl font-bold leading-none"
|
|
45
|
+
href={logoLink(logo)}
|
|
46
|
+
target={logo?.linkTarget}
|
|
47
|
+
rel={logo?.linkTarget === "_blank" ? "noopener noreferrer" : ""}>
|
|
48
|
+
<Image
|
|
49
|
+
src={logo?.image}
|
|
50
|
+
alt={logo?.alt ?? "signup-logo"}
|
|
51
|
+
width={100}
|
|
52
|
+
height={100}
|
|
53
|
+
className="flex justify-center mx-auto text-3xl font-bold leading-none"
|
|
54
|
+
/>
|
|
55
|
+
</Link>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function SubtitleAndHeadingText({ form }: { form?: iForm }) {
|
|
61
|
+
return (
|
|
62
|
+
<div className="mb-6">
|
|
63
|
+
{form?.subtitle ? <Text muted>{form?.subtitle}</Text> : null}
|
|
64
|
+
{form?.name ? <Heading className="text-2xl lg:text-2xl">{form?.name}</Heading> : null}
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function SignupForm({
|
|
70
|
+
form,
|
|
71
|
+
signInLink,
|
|
72
|
+
thankYouPage,
|
|
73
|
+
}: {
|
|
74
|
+
form?: iForm;
|
|
75
|
+
signInLink?: LabeledRoute;
|
|
76
|
+
thankYouPage?: LabeledRoute;
|
|
77
|
+
}) {
|
|
78
|
+
if (!form?.fields) return null;
|
|
79
|
+
const [showPassword, setShowPassword] = React.useState(false);
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<Form
|
|
83
|
+
id={form?.id ?? undefined}
|
|
84
|
+
name="SignUp-VariantA-Form"
|
|
85
|
+
className="form-signup"
|
|
86
|
+
thankyouPage={thankYouPage}>
|
|
87
|
+
<FormFields form={form} showPassword={showPassword} setShowPassword={setShowPassword} />
|
|
88
|
+
<div>
|
|
89
|
+
<div className="webriq-recaptcha" />
|
|
90
|
+
</div>
|
|
91
|
+
<div className="text-center">
|
|
92
|
+
{form?.buttonLabel && (
|
|
93
|
+
<Button
|
|
94
|
+
as="button"
|
|
95
|
+
variant="custom"
|
|
96
|
+
ariaLabel={form?.buttonLabel ?? "Sign Up form submit button"}
|
|
97
|
+
className="w-full py-4 text-sm font-bold tex-gray-50"
|
|
98
|
+
type="submit">
|
|
99
|
+
{form?.buttonLabel}
|
|
100
|
+
</Button>
|
|
101
|
+
)}
|
|
102
|
+
</div>
|
|
103
|
+
{signInLink && <SignInLink signInLink={signInLink} />}
|
|
104
|
+
</Form>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function FormFields({
|
|
109
|
+
form,
|
|
110
|
+
showPassword,
|
|
111
|
+
setShowPassword,
|
|
112
|
+
}: {
|
|
113
|
+
form?: iForm;
|
|
114
|
+
showPassword: boolean;
|
|
115
|
+
setShowPassword: React.Dispatch<React.SetStateAction<boolean>>;
|
|
116
|
+
}) {
|
|
117
|
+
return (
|
|
118
|
+
<>
|
|
119
|
+
<Flex wrap className="-mx-2">
|
|
120
|
+
{form?.fields?.slice(0, 2).map((formFields, index) => (
|
|
121
|
+
<div className="w-full px-2 mb-3 lg:w-1/2" key={index}>
|
|
122
|
+
{formFields.type === "inputText" ? (
|
|
123
|
+
<Input
|
|
124
|
+
textSize="sm"
|
|
125
|
+
variant="primary"
|
|
126
|
+
noLabel
|
|
127
|
+
placeholder={formFields?.placeholder}
|
|
128
|
+
required={formFields?.isRequired}
|
|
129
|
+
className="w-full py-4 text-xs bg-white"
|
|
130
|
+
name={formFields?.name}
|
|
131
|
+
ariaLabel={formFields?.label}
|
|
132
|
+
{...formFields}
|
|
133
|
+
type="text"
|
|
134
|
+
/>
|
|
135
|
+
) : (
|
|
136
|
+
<FormField textSize="sm" noLabel name={formFields?.name ?? ""} {...formFields} />
|
|
137
|
+
)}
|
|
138
|
+
</div>
|
|
139
|
+
))}
|
|
140
|
+
</Flex>
|
|
141
|
+
{form?.fields?.slice(2).map((formFields, index) => (
|
|
142
|
+
<div key={index} className="my-3">
|
|
143
|
+
{formFields.type === "inputPassword" ? (
|
|
144
|
+
<PasswordField
|
|
145
|
+
formFields={formFields}
|
|
146
|
+
showPassword={showPassword}
|
|
147
|
+
setShowPassword={setShowPassword}
|
|
148
|
+
/>
|
|
149
|
+
) : (
|
|
150
|
+
<FormField
|
|
151
|
+
className="py-4"
|
|
152
|
+
textSize="sm"
|
|
153
|
+
noLabel
|
|
154
|
+
variant="primary"
|
|
155
|
+
placeholder={formFields?.placeholder}
|
|
156
|
+
required={formFields?.isRequired}
|
|
157
|
+
name={formFields?.name ?? ""}
|
|
158
|
+
items={formFields?.items}
|
|
159
|
+
type={formFields?.type}
|
|
160
|
+
{...formFields}
|
|
161
|
+
/>
|
|
162
|
+
)}
|
|
163
|
+
</div>
|
|
164
|
+
))}
|
|
165
|
+
</>
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function SignInLink({ signInLink }: { signInLink?: LabeledRoute }) {
|
|
170
|
+
if (!signInLink?.label) return null;
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<div className="w-full text-center mt-3">
|
|
174
|
+
<span className="text-xs text-gray-500">Already have an account? </span>
|
|
175
|
+
<Button
|
|
176
|
+
as="link"
|
|
177
|
+
variant="link"
|
|
178
|
+
link={signInLink}
|
|
179
|
+
className="text-xs text-primary cursor-pointer hover:underline"
|
|
180
|
+
ariaLabel={signInLink?.label}>
|
|
181
|
+
{signInLink?.label}
|
|
182
|
+
</Button>
|
|
183
|
+
</div>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function PasswordField({
|
|
188
|
+
formFields,
|
|
189
|
+
showPassword,
|
|
190
|
+
setShowPassword,
|
|
191
|
+
}: {
|
|
192
|
+
formFields?: any;
|
|
193
|
+
showPassword: boolean;
|
|
194
|
+
setShowPassword: React.Dispatch<React.SetStateAction<boolean>>;
|
|
195
|
+
}) {
|
|
196
|
+
return (
|
|
197
|
+
<Flex className="relative">
|
|
198
|
+
<Input
|
|
199
|
+
className="py-4"
|
|
200
|
+
textSize="sm"
|
|
201
|
+
noLabel
|
|
202
|
+
aria-label={formFields?.placeholder ?? formFields?.name}
|
|
203
|
+
variant="primary"
|
|
204
|
+
type={showPassword ? "text" : "password"}
|
|
205
|
+
placeholder={formFields?.placeholder}
|
|
206
|
+
name={formFields?.name}
|
|
207
|
+
required={formFields?.isRequired}
|
|
208
|
+
/>
|
|
209
|
+
<Button
|
|
210
|
+
as="button"
|
|
211
|
+
variant="unstyled"
|
|
212
|
+
ariaLabel={showPassword ? "Show password" : "Hide password"}
|
|
213
|
+
className="absolute top-0 right-0 h-full p-2"
|
|
214
|
+
type="button"
|
|
215
|
+
onClick={() => setShowPassword(!showPassword)}>
|
|
216
|
+
<PasswordIcon showPassword={showPassword} />
|
|
217
|
+
</Button>
|
|
218
|
+
</Flex>
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function FormLinks({ formLinks }: { formLinks?: LabeledRouteWithKey[] }) {
|
|
223
|
+
if (!formLinks) return null;
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<p className="mt-10 text-xs text-center text-gray-700">
|
|
227
|
+
{formLinks?.map((link: any, index: number, { length }: any) => (
|
|
228
|
+
<span key={index}>
|
|
229
|
+
<Button
|
|
230
|
+
as="link"
|
|
231
|
+
variant="link"
|
|
232
|
+
link={link}
|
|
233
|
+
className="text-xs text-primary cursor-pointer hover:underline"
|
|
234
|
+
ariaLabel={link?.label}>
|
|
235
|
+
{link?.label}
|
|
236
|
+
</Button>
|
|
237
|
+
{index === length - 1 ? null : index === length - 2 ? (
|
|
238
|
+
<span> and </span>
|
|
239
|
+
) : (
|
|
240
|
+
<span> , </span>
|
|
241
|
+
)}
|
|
242
|
+
</span>
|
|
243
|
+
))}
|
|
244
|
+
</p>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function PasswordIcon({ showPassword }: { showPassword: boolean }) {
|
|
249
|
+
return (
|
|
250
|
+
<>
|
|
251
|
+
{showPassword ? (
|
|
252
|
+
<svg
|
|
253
|
+
className="w-5 h-5 my-auto ml-4 text-gray-500"
|
|
254
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
255
|
+
aria-hidden="true"
|
|
256
|
+
role="img"
|
|
257
|
+
width="1em"
|
|
258
|
+
height="1em"
|
|
259
|
+
preserveAspectRatio="xMidYMid meet"
|
|
260
|
+
viewBox="0 0 16 16">
|
|
261
|
+
<g fill="currentColor">
|
|
262
|
+
<path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944 5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288c-.335.48-.83 1.12-1.465 1.755c-.165.165-.337.328-.517.486l.708.709z" />
|
|
263
|
+
<path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943 1.299l.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z" />
|
|
264
|
+
<path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884l-12-12l.708-.708l12 12l-.708.708z" />
|
|
265
|
+
</g>
|
|
266
|
+
</svg>
|
|
267
|
+
) : (
|
|
268
|
+
<svg
|
|
269
|
+
className="w-5 h-5 my-auto ml-4 text-gray-500"
|
|
270
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
271
|
+
aria-hidden="true"
|
|
272
|
+
role="img"
|
|
273
|
+
width="1em"
|
|
274
|
+
height="1em"
|
|
275
|
+
preserveAspectRatio="xMidYMid meet"
|
|
276
|
+
viewBox="0 0 16 16">
|
|
277
|
+
<g fill="currentColor">
|
|
278
|
+
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z" />
|
|
279
|
+
<path d="M8 5.5a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0a3.5 3.5 0 0 1-7 0z" />
|
|
280
|
+
</g>
|
|
281
|
+
</svg>
|
|
282
|
+
)}
|
|
283
|
+
</>
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export { SigninSignup_A };
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { Button } from "@stackshift-ui/button";
|
|
2
|
+
import { Card } from "@stackshift-ui/card";
|
|
3
|
+
import { Container } from "@stackshift-ui/container";
|
|
4
|
+
import { Flex } from "@stackshift-ui/flex";
|
|
5
|
+
import { Form } from "@stackshift-ui/form";
|
|
6
|
+
import { FormField } from "@stackshift-ui/form-field";
|
|
7
|
+
import { Heading } from "@stackshift-ui/heading";
|
|
8
|
+
import { Image } from "@stackshift-ui/image";
|
|
9
|
+
import { Input } from "@stackshift-ui/input";
|
|
10
|
+
import { Link } from "@stackshift-ui/link";
|
|
11
|
+
import { Section } from "@stackshift-ui/section";
|
|
12
|
+
import { Text } from "@stackshift-ui/text";
|
|
13
|
+
import React, { useState } from "react";
|
|
14
|
+
import { SignUpFormProps } from ".";
|
|
15
|
+
import { logoLink, thankYouPageLink } from "./helper";
|
|
16
|
+
import { LabeledRoute, Logo, Form as iForm } from "./types";
|
|
17
|
+
|
|
18
|
+
export default function SigninSignup_B({ logo, form, formLinks, signInLink }: SignUpFormProps) {
|
|
19
|
+
return (
|
|
20
|
+
<Section className="py-10 bg-primary lg:py-20">
|
|
21
|
+
<Container maxWidth={1280}>
|
|
22
|
+
<Container maxWidth={576}>
|
|
23
|
+
<LogoSection logo={logo} />
|
|
24
|
+
<Card className="p-6 mb-6 bg-white lg:mb-10 lg:p-12">
|
|
25
|
+
<SubtitleAndHeadingText form={form} />
|
|
26
|
+
<SignupForm form={form} signInLink={signInLink} />
|
|
27
|
+
</Card>
|
|
28
|
+
<FormLinks formLinks={formLinks} />
|
|
29
|
+
</Container>
|
|
30
|
+
</Container>
|
|
31
|
+
</Section>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function LogoSection({ logo }: { logo?: Logo }) {
|
|
36
|
+
if (!logo) return null;
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div className="mb-10">
|
|
40
|
+
<Link
|
|
41
|
+
aria-label={`Go to ${logoLink(logo) === "/" ? "home page" : logoLink(logo)}`}
|
|
42
|
+
className="flex justify-center mx-auto text-3xl font-bold leading-none"
|
|
43
|
+
href={logoLink(logo)}
|
|
44
|
+
target={logo?.linkTarget}
|
|
45
|
+
rel={logo?.linkTarget === "_blank" ? "noopener noreferrer" : ""}>
|
|
46
|
+
<Image
|
|
47
|
+
src={logo?.image}
|
|
48
|
+
alt={logo?.alt ?? "signup-logo"}
|
|
49
|
+
width={100}
|
|
50
|
+
height={100}
|
|
51
|
+
className="flex justify-center text-3xl font-bold leading-none text-white"
|
|
52
|
+
/>
|
|
53
|
+
</Link>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function SubtitleAndHeadingText({ form }: { form?: iForm }) {
|
|
59
|
+
return (
|
|
60
|
+
<div className="mb-6">
|
|
61
|
+
<Text muted>{form?.subtitle}</Text>
|
|
62
|
+
<Heading className="text-2xl lg:text-2xl">{form?.name}</Heading>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function SignupForm({ form, signInLink }: { form?: iForm; signInLink?: LabeledRoute }) {
|
|
68
|
+
if (!form?.fields) return null;
|
|
69
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<Form
|
|
73
|
+
id={form?.id ?? undefined}
|
|
74
|
+
name="SignUp-VariantB-Form"
|
|
75
|
+
className="form-signup"
|
|
76
|
+
thankyouPage={thankYouPageLink(form?.thankYouPage)}>
|
|
77
|
+
<FormFields form={form} showPassword={showPassword} setShowPassword={setShowPassword} />
|
|
78
|
+
<div>
|
|
79
|
+
<div className="webriq-recaptcha" />
|
|
80
|
+
</div>
|
|
81
|
+
<div className="text-center">
|
|
82
|
+
<FormButtonLabel form={form} />
|
|
83
|
+
<SigninLink signInLink={signInLink} />
|
|
84
|
+
</div>
|
|
85
|
+
</Form>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function FormFields({
|
|
90
|
+
form,
|
|
91
|
+
showPassword,
|
|
92
|
+
setShowPassword,
|
|
93
|
+
}: {
|
|
94
|
+
form?: iForm;
|
|
95
|
+
showPassword: boolean;
|
|
96
|
+
setShowPassword: React.Dispatch<React.SetStateAction<boolean>>;
|
|
97
|
+
}) {
|
|
98
|
+
return (
|
|
99
|
+
<React.Fragment>
|
|
100
|
+
<Flex className="flex-col lg:flex-row gap-3">
|
|
101
|
+
{form?.fields?.slice(0, 2)?.map((formFields, index) => (
|
|
102
|
+
<div className="w-full" key={index}>
|
|
103
|
+
<FormField
|
|
104
|
+
noLabel
|
|
105
|
+
variant="secondary"
|
|
106
|
+
placeholder={formFields?.placeholder}
|
|
107
|
+
required={formFields?.isRequired}
|
|
108
|
+
name={formFields?.name ?? ""}
|
|
109
|
+
items={formFields?.items}
|
|
110
|
+
type={formFields?.type}
|
|
111
|
+
{...formFields}
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
))}
|
|
115
|
+
</Flex>
|
|
116
|
+
|
|
117
|
+
{form?.fields?.slice(2)?.map((formFields, index) => (
|
|
118
|
+
<div key={index} className="my-3">
|
|
119
|
+
{formFields?.type === "inputPassword" ? (
|
|
120
|
+
<div className="flex">
|
|
121
|
+
<Input
|
|
122
|
+
noLabel
|
|
123
|
+
ariaLabel={formFields?.placeholder ?? formFields?.name}
|
|
124
|
+
variant="secondary"
|
|
125
|
+
type={showPassword ? "text" : "password"}
|
|
126
|
+
placeholder={formFields?.placeholder}
|
|
127
|
+
name={formFields?.name}
|
|
128
|
+
required={formFields?.isRequired}
|
|
129
|
+
/>
|
|
130
|
+
{/* SVG icon on the right of the password input field */}
|
|
131
|
+
<Button
|
|
132
|
+
variant="unstyled"
|
|
133
|
+
as="button"
|
|
134
|
+
ariaLabel={showPassword ? "Show password" : "Hide password"}
|
|
135
|
+
className="focus:outline-none mr-4"
|
|
136
|
+
type="button"
|
|
137
|
+
onClick={() => setShowPassword(!showPassword)}>
|
|
138
|
+
<PasswordIcon showPassword={showPassword} />
|
|
139
|
+
</Button>
|
|
140
|
+
</div>
|
|
141
|
+
) : (
|
|
142
|
+
<FormField
|
|
143
|
+
noLabel
|
|
144
|
+
variant="secondary"
|
|
145
|
+
name={formFields?.name ?? ""}
|
|
146
|
+
placeholder={formFields?.placeholder}
|
|
147
|
+
required={formFields?.isRequired}
|
|
148
|
+
items={formFields?.items}
|
|
149
|
+
type={formFields?.type}
|
|
150
|
+
{...formFields}
|
|
151
|
+
/>
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
))}
|
|
155
|
+
</React.Fragment>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function FormButtonLabel({ form }: { form?: iForm }) {
|
|
160
|
+
if (!form?.buttonLabel) return null;
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<Button
|
|
164
|
+
as="button"
|
|
165
|
+
className="w-full py-4 mb-3"
|
|
166
|
+
ariaLabel={form?.buttonLabel ?? "Sign Up form submit button"}
|
|
167
|
+
variant="custom"
|
|
168
|
+
type="submit">
|
|
169
|
+
{form?.buttonLabel}
|
|
170
|
+
</Button>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function SigninLink({ signInLink }: { signInLink?: LabeledRoute }) {
|
|
175
|
+
if (!signInLink?.label) return null;
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<span className="text-xs text-gray-900">
|
|
179
|
+
<span>Already have an account?</span>{" "}
|
|
180
|
+
<Button
|
|
181
|
+
as="link"
|
|
182
|
+
variant="link"
|
|
183
|
+
link={signInLink}
|
|
184
|
+
className="text-xs text-primary hover:underline"
|
|
185
|
+
ariaLabel={signInLink?.label}>
|
|
186
|
+
{signInLink?.label}
|
|
187
|
+
</Button>
|
|
188
|
+
</span>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function FormLinks({ formLinks }: { formLinks?: LabeledRoute[] }) {
|
|
193
|
+
if (!formLinks) return null;
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<p className="text-xs text-center text-secondary-foreground">
|
|
197
|
+
{formLinks?.map((link, index, { length }) => (
|
|
198
|
+
<span key={index}>
|
|
199
|
+
<Button
|
|
200
|
+
as="link"
|
|
201
|
+
variant="link"
|
|
202
|
+
link={link}
|
|
203
|
+
className="text-xs underline text-secondary-foreground hover:text-gray-50"
|
|
204
|
+
ariaLabel={link?.label}>
|
|
205
|
+
{link?.label}
|
|
206
|
+
</Button>
|
|
207
|
+
{index === length - 1 ? null : index === length - 2 ? (
|
|
208
|
+
<span> and </span>
|
|
209
|
+
) : (
|
|
210
|
+
<span> , </span>
|
|
211
|
+
)}
|
|
212
|
+
</span>
|
|
213
|
+
))}
|
|
214
|
+
</p>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function PasswordIcon({ showPassword }: { showPassword: boolean }) {
|
|
219
|
+
return (
|
|
220
|
+
<React.Fragment>
|
|
221
|
+
{showPassword ? (
|
|
222
|
+
<svg
|
|
223
|
+
className="w-5 h-5 my-auto text-gray-500"
|
|
224
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
225
|
+
aria-hidden="true"
|
|
226
|
+
role="img"
|
|
227
|
+
width="1em"
|
|
228
|
+
height="1em"
|
|
229
|
+
preserveAspectRatio="xMidYMid meet"
|
|
230
|
+
viewBox="0 0 16 16">
|
|
231
|
+
<g fill="currentColor">
|
|
232
|
+
<path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944 5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288c-.335.48-.83 1.12-1.465 1.755c-.165.165-.337.328-.517.486l.708.709z" />
|
|
233
|
+
<path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943 1.299l.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z" />
|
|
234
|
+
<path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884l-12-12l.708-.708l12 12l-.708.708z" />
|
|
235
|
+
</g>
|
|
236
|
+
</svg>
|
|
237
|
+
) : (
|
|
238
|
+
<svg
|
|
239
|
+
className="w-5 h-5 my-auto ml-4 text-gray-500"
|
|
240
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
241
|
+
aria-hidden="true"
|
|
242
|
+
role="img"
|
|
243
|
+
width="1em"
|
|
244
|
+
height="1em"
|
|
245
|
+
preserveAspectRatio="xMidYMid meet"
|
|
246
|
+
viewBox="0 0 16 16">
|
|
247
|
+
<g fill="currentColor">
|
|
248
|
+
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z" />
|
|
249
|
+
<path d="M8 5.5a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0a3.5 3.5 0 0 1-7 0z" />
|
|
250
|
+
</g>
|
|
251
|
+
</svg>
|
|
252
|
+
)}
|
|
253
|
+
</React.Fragment>
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export { SigninSignup_B };
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
export type StyleVariants<T extends string> = Record<T, string>;
|
|
2
|
+
|
|
3
|
+
export type Socials = "facebook" | "instagram" | "youtube" | "linkedin" | "twitter";
|
|
4
|
+
export interface MainImage {
|
|
5
|
+
image: string;
|
|
6
|
+
alt?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface LabeledRoute extends ConditionalLink {
|
|
10
|
+
ariaLabel?: string;
|
|
11
|
+
label?: string;
|
|
12
|
+
linkTarget?: string;
|
|
13
|
+
linkType?: string;
|
|
14
|
+
_type?: string;
|
|
15
|
+
linkInternal?: any;
|
|
16
|
+
}
|
|
17
|
+
export interface ConditionalLink {
|
|
18
|
+
type?: string;
|
|
19
|
+
internalLink?: string | null;
|
|
20
|
+
externalLink?: string | null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface StatItems {
|
|
24
|
+
label?: string;
|
|
25
|
+
mainImage?: MainImage;
|
|
26
|
+
value?: string;
|
|
27
|
+
_key?: string;
|
|
28
|
+
_type?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface Logo extends ConditionalLink {
|
|
32
|
+
alt?: string;
|
|
33
|
+
linkTarget?: string;
|
|
34
|
+
image?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface Images {
|
|
38
|
+
image?: string;
|
|
39
|
+
_key?: string;
|
|
40
|
+
_type?: string;
|
|
41
|
+
alt?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ContactDetails {
|
|
45
|
+
addressInfo?: string;
|
|
46
|
+
contactInfo?: string;
|
|
47
|
+
emailInfo?: string;
|
|
48
|
+
_key?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface SocialLink {
|
|
52
|
+
socialMedia?: string | null;
|
|
53
|
+
socialMediaLink?: string | null;
|
|
54
|
+
_key?: string | null;
|
|
55
|
+
_type?: string | null;
|
|
56
|
+
socialMediaIcon?: {
|
|
57
|
+
alt?: string;
|
|
58
|
+
image?: string;
|
|
59
|
+
} | null;
|
|
60
|
+
socialMediaPlatform?: string | null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface LabeledRouteWithKey extends LabeledRoute {
|
|
64
|
+
_key?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface ArrayOfImageTitleAndText {
|
|
68
|
+
mainImage?: {
|
|
69
|
+
alt?: string;
|
|
70
|
+
image?: string;
|
|
71
|
+
};
|
|
72
|
+
plainText?: string;
|
|
73
|
+
title?: string;
|
|
74
|
+
_key?: string;
|
|
75
|
+
_type?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface FeaturedItem {
|
|
79
|
+
description?: string;
|
|
80
|
+
mainImage?: MainImage;
|
|
81
|
+
title?: string;
|
|
82
|
+
subtitle?: string;
|
|
83
|
+
_key?: string;
|
|
84
|
+
_type?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface ArrayOfTitleAndText {
|
|
88
|
+
_key?: string;
|
|
89
|
+
plainText?: string;
|
|
90
|
+
title?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface BlogPost extends SanityBody {
|
|
94
|
+
authors?: Author[] | null;
|
|
95
|
+
body?: any;
|
|
96
|
+
categories?: Category[] | null;
|
|
97
|
+
excerpt?: string | null;
|
|
98
|
+
link?: string | null;
|
|
99
|
+
mainImage?: string | null;
|
|
100
|
+
publishedAt?: string;
|
|
101
|
+
seo?: Seo | null;
|
|
102
|
+
slug?: SanitySlug | null;
|
|
103
|
+
title?: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface Seo {
|
|
107
|
+
_type?: string;
|
|
108
|
+
seoTitle?: string;
|
|
109
|
+
seoDescription?: string;
|
|
110
|
+
seoImage?: string;
|
|
111
|
+
seoKeywords?: string;
|
|
112
|
+
seoSynonyms?: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface SanitySlug {
|
|
116
|
+
current?: string;
|
|
117
|
+
_type?: "slug";
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface SanityBody {
|
|
121
|
+
_createdAt?: string;
|
|
122
|
+
_id?: string;
|
|
123
|
+
_rev?: string;
|
|
124
|
+
_type?: string;
|
|
125
|
+
_updatedAt?: string;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface Author extends SanityBody {
|
|
129
|
+
link?: string | null;
|
|
130
|
+
bio?: string | null;
|
|
131
|
+
name?: string | null;
|
|
132
|
+
slug?: SanitySlug | null;
|
|
133
|
+
image?: string | null;
|
|
134
|
+
profile?: {
|
|
135
|
+
alt: string;
|
|
136
|
+
image: string;
|
|
137
|
+
} | null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface Category extends SanityBody {
|
|
141
|
+
title?: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface Form {
|
|
145
|
+
id?: string | null;
|
|
146
|
+
buttonLabel?: string | null;
|
|
147
|
+
name?: string | null;
|
|
148
|
+
subtitle?: string | null;
|
|
149
|
+
fields?: FormFields[] | null;
|
|
150
|
+
thankYouPage?: ThankYouPage | null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface FormFields {
|
|
154
|
+
name?: string;
|
|
155
|
+
placeholder?: string;
|
|
156
|
+
pricingType?: string;
|
|
157
|
+
type?: FormTypes;
|
|
158
|
+
_key?: string;
|
|
159
|
+
_type?: string;
|
|
160
|
+
isRequired?: boolean;
|
|
161
|
+
label?: string;
|
|
162
|
+
items?: string[];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export type FormTypes =
|
|
166
|
+
| "inputText"
|
|
167
|
+
| "inputEmail"
|
|
168
|
+
| "inputPassword"
|
|
169
|
+
| "inputNumber"
|
|
170
|
+
| "textarea"
|
|
171
|
+
| "inputFile"
|
|
172
|
+
| "inputRadio"
|
|
173
|
+
| "inputCheckbox"
|
|
174
|
+
| "inputSelect";
|
|
175
|
+
|
|
176
|
+
export interface ThankYouPage {
|
|
177
|
+
externalLink?: string | null;
|
|
178
|
+
internalLink?: string | null;
|
|
179
|
+
linkInternal?: any;
|
|
180
|
+
linkTarget?: string;
|
|
181
|
+
linkType?: string;
|
|
182
|
+
type?: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
//Used on different sections
|
|
186
|
+
export interface SectionsProps {
|
|
187
|
+
template?: Template;
|
|
188
|
+
data?: Sections;
|
|
189
|
+
variant?: string | null | undefined;
|
|
190
|
+
schema?: Variants;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface Sections extends SanityBody {
|
|
194
|
+
label?: string;
|
|
195
|
+
variant?: string;
|
|
196
|
+
variants?: Variants;
|
|
197
|
+
_key?: string;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
//*EDIT THIS SECTION WHEN CREATING/UPDATING SCHEMAS ON STUDIO */
|
|
201
|
+
export interface Variants {
|
|
202
|
+
template?: Template;
|
|
203
|
+
multipleMenus?: any;
|
|
204
|
+
arrayOfTitleAndText?: ArrayOfTitleAndText[] | null;
|
|
205
|
+
logo?: Logo | null;
|
|
206
|
+
primaryButton?: LabeledRoute | null;
|
|
207
|
+
secondaryButton?: LabeledRoute | null;
|
|
208
|
+
routes?: LabeledRouteWithKey[] | null;
|
|
209
|
+
menu?: LabeledRouteWithKey[] | null;
|
|
210
|
+
plans?: Plans[] | null;
|
|
211
|
+
formLinks?: LabeledRouteWithKey[] | null;
|
|
212
|
+
portfolios?: Portfolios[] | null;
|
|
213
|
+
portfoliosWithCategories?: PortfoliosWithCategories[] | null;
|
|
214
|
+
length?: number;
|
|
215
|
+
signInLink?: LabeledRoute | null;
|
|
216
|
+
signinLink?: LabeledRoute | null;
|
|
217
|
+
tags?: string[] | null;
|
|
218
|
+
posts?: BlogPost[] | null;
|
|
219
|
+
blogsPerPage?: number | null;
|
|
220
|
+
form?: Form | null;
|
|
221
|
+
collections?: Collection | null;
|
|
222
|
+
products?: CollectionProduct | null;
|
|
223
|
+
allProducts?: Collection[];
|
|
224
|
+
subtitle?: string | null;
|
|
225
|
+
caption?: string | null;
|
|
226
|
+
title?: string | null;
|
|
227
|
+
plainText?: string | null;
|
|
228
|
+
contactDescription?: string | null;
|
|
229
|
+
officeInformation?: string | null;
|
|
230
|
+
contactEmail?: string | null;
|
|
231
|
+
contactNumber?: string | null;
|
|
232
|
+
socialLinks?: SocialLink[] | null;
|
|
233
|
+
block?: any;
|
|
234
|
+
heading?: string | null;
|
|
235
|
+
acceptButtonLabel?: string | null;
|
|
236
|
+
declineButtonLabel?: string | null;
|
|
237
|
+
faqsWithCategories?: FaqsWithCategory[] | null;
|
|
238
|
+
faqs?: AskedQuestion[] | null;
|
|
239
|
+
arrayOfImageTitleAndText?: ArrayOfImageTitleAndText[] | null;
|
|
240
|
+
description?: string | null;
|
|
241
|
+
featuredItems?: FeaturedItem[] | null;
|
|
242
|
+
images?: Images[] | null;
|
|
243
|
+
contactDetails?: ContactDetails[] | null;
|
|
244
|
+
copyright?: string | null;
|
|
245
|
+
mainImage?: MainImage | null;
|
|
246
|
+
youtubeLink?: string | null;
|
|
247
|
+
banner?: any;
|
|
248
|
+
stats?: StatItems[] | null;
|
|
249
|
+
teams?: Team[] | null;
|
|
250
|
+
testimonials?: Testimonial[] | null;
|
|
251
|
+
selectStripeAccount?: string;
|
|
252
|
+
annualBilling?: string;
|
|
253
|
+
monthlyBilling?: string;
|
|
254
|
+
productDetails?: ProductDetail[];
|
|
255
|
+
btnLabel?: string;
|
|
256
|
+
selectAccount?: string;
|
|
257
|
+
hashtags?: string[];
|
|
258
|
+
numberOfPosts?: number;
|
|
259
|
+
text?: string;
|
|
260
|
+
button?: LabeledRoute;
|
|
261
|
+
features?: string[];
|
|
262
|
+
config?: {
|
|
263
|
+
enableAnalytics: boolean;
|
|
264
|
+
cookiePolicy?: {
|
|
265
|
+
siteName: string;
|
|
266
|
+
cookiePolicyPage: Reference;
|
|
267
|
+
};
|
|
268
|
+
consentModalPosition?: string;
|
|
269
|
+
};
|
|
270
|
+
contactLink?: LabeledRoute;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export interface Template {
|
|
274
|
+
bg?: string;
|
|
275
|
+
color?: string;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export type Plans = {
|
|
279
|
+
_key?: string | null;
|
|
280
|
+
_type?: "planItems" | null;
|
|
281
|
+
checkoutButtonName?: string | null;
|
|
282
|
+
description?: string | null;
|
|
283
|
+
monthlyPrice?: string | null;
|
|
284
|
+
planType?: string | null;
|
|
285
|
+
yearlyPrice?: string | null;
|
|
286
|
+
planIncludes?: string[] | null;
|
|
287
|
+
primaryButton?: LabeledRoute | null;
|
|
288
|
+
} & Record<string, string>;
|
|
289
|
+
|
|
290
|
+
export interface Portfolios {
|
|
291
|
+
dateAdded?: string | null;
|
|
292
|
+
mainImage?: {
|
|
293
|
+
image?: string | null;
|
|
294
|
+
alt?: string | null;
|
|
295
|
+
} | null;
|
|
296
|
+
primaryButton?: LabeledRoute | null;
|
|
297
|
+
title?: string | null;
|
|
298
|
+
_key?: string | null;
|
|
299
|
+
_type?: string | null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface PortfoliosWithCategories {
|
|
303
|
+
category?: string | null;
|
|
304
|
+
content?: Content[] | null;
|
|
305
|
+
primaryButton?: LabeledRoute | null;
|
|
306
|
+
_key?: string | null;
|
|
307
|
+
_type?: string | null;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export interface Content extends Portfolios {
|
|
311
|
+
description?: string | null;
|
|
312
|
+
subtitle?: string | null;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export interface Collection extends SanityBody {
|
|
316
|
+
collectionInfoVariant?: {
|
|
317
|
+
variant?: string;
|
|
318
|
+
} | null;
|
|
319
|
+
name?: string | null;
|
|
320
|
+
products?: CollectionProduct[] | null;
|
|
321
|
+
sections?: any; //todo
|
|
322
|
+
seo?: Seo | null;
|
|
323
|
+
slug?: SanitySlug | null;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export interface CollectionProduct extends SanityBody {
|
|
327
|
+
compareToPrice?: number | null;
|
|
328
|
+
description?: string | null;
|
|
329
|
+
ecwidProductId?: number | null;
|
|
330
|
+
name?: string | null;
|
|
331
|
+
price?: number | null;
|
|
332
|
+
productInfo?: ProductInfo | null;
|
|
333
|
+
productInfoVariant?: {
|
|
334
|
+
variant?: string;
|
|
335
|
+
} | null;
|
|
336
|
+
sections?: any; //todo
|
|
337
|
+
seo?: Seo | null;
|
|
338
|
+
slug?: SanitySlug | null;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
//TODO, RECHECK PRODUCT INFO DATA FROM SANITY
|
|
342
|
+
interface ProductInfo {
|
|
343
|
+
btnLabel?: string | null;
|
|
344
|
+
images?: ProductInfoImage[] | null;
|
|
345
|
+
productDetails?: ProductDetail[] | null;
|
|
346
|
+
socialLinks?: SocialLink[] | null;
|
|
347
|
+
subtitle?: string | null;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
//TODO, RECHECK PRODUCT INFO DATA FROM SANITY
|
|
351
|
+
export interface ProductDetail {
|
|
352
|
+
blockContent?: any;
|
|
353
|
+
contentType?: string;
|
|
354
|
+
tabName?: string;
|
|
355
|
+
_key?: string;
|
|
356
|
+
[key: string]: any;
|
|
357
|
+
}
|
|
358
|
+
interface ProductInfoImage {
|
|
359
|
+
alt?: string | null;
|
|
360
|
+
_key: string;
|
|
361
|
+
_type: string;
|
|
362
|
+
image?: string | null;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export interface FaqsWithCategory {
|
|
366
|
+
askedQuestions?: AskedQuestion[] | null;
|
|
367
|
+
category?: string | null;
|
|
368
|
+
_key?: string;
|
|
369
|
+
_type?: string;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export interface AskedQuestion {
|
|
373
|
+
answer?: string | null;
|
|
374
|
+
question?: string | null;
|
|
375
|
+
hidden?: boolean;
|
|
376
|
+
_key?: string;
|
|
377
|
+
_type?: string;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export interface Team {
|
|
381
|
+
jobTitle?: string;
|
|
382
|
+
mainImage?: MainImage;
|
|
383
|
+
name?: string;
|
|
384
|
+
plainText?: string;
|
|
385
|
+
_key?: string;
|
|
386
|
+
_type?: string;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export interface Testimonial {
|
|
390
|
+
jobTitle?: string;
|
|
391
|
+
mainImage?: MainImage;
|
|
392
|
+
name?: string;
|
|
393
|
+
rating?: string;
|
|
394
|
+
testimony?: string;
|
|
395
|
+
_key?: string;
|
|
396
|
+
_type?: string;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export declare interface Reference {
|
|
400
|
+
_type: string;
|
|
401
|
+
_ref: string;
|
|
402
|
+
_key?: string;
|
|
403
|
+
_weak?: boolean;
|
|
404
|
+
_strengthenOnPublish?: {
|
|
405
|
+
type: string;
|
|
406
|
+
weak?: boolean;
|
|
407
|
+
template?: {
|
|
408
|
+
id: string;
|
|
409
|
+
params: Record<string, string | number | boolean>;
|
|
410
|
+
};
|
|
411
|
+
};
|
|
412
|
+
}
|