Skip to content

Commit c5cc1f0

Browse files
Justin MakailaJustin Makaila
authored andcommitted
initial commit
1 parent 0404292 commit c5cc1f0

File tree

40 files changed

+4047
-1020
lines changed

40 files changed

+4047
-1020
lines changed

.DS_Store

6 KB
Binary file not shown.

.pnp.cjs

Lines changed: 2138 additions & 869 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
{
2-
"name": "typescript-react-s3-website-site",
2+
"name": "marketing-site",
33
"version": "0.0.1",
44
"private": true,
55
"email": "[email protected]",
6-
"homepage": "https://treehousetechnology.github.io/react-typescript-s3-template/",
76
"license": "MIT",
87
"scripts": {
98
"build": "node scripts/build.js",
@@ -15,9 +14,17 @@
1514
"typecheck": "tsc"
1615
},
1716
"dependencies": {
17+
"@react-navigation/native": "^6.1.7",
18+
"@react-navigation/native-stack": "^6.9.13",
19+
"@react-navigation/stack": "^6.3.17",
20+
"i18n-js": "^4.3.0",
21+
"lodash": "^4.17.21",
1822
"react": "^18.2.0",
1923
"react-app-polyfill": "^3.0.0",
2024
"react-dom": "^18.2.0",
25+
"react-hook-form": "^7.46.0",
26+
"react-native-localize": "^3.0.2",
27+
"react-native-safe-area-context": "^4.7.2",
2128
"react-native-web": "^0.19.8",
2229
"react-refresh": "^0.11",
2330
"react-router-dom": "^6",
@@ -28,11 +35,13 @@
2835
"@babel/plugin-proposal-class-properties": "^7.16.0",
2936
"@babel/runtime": "^7.22.11",
3037
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
38+
"@storybook/react": "^7.4.0",
3139
"@svgr/webpack": "^8.1.0",
3240
"@testing-library/jest-dom": "^6.1.2",
3341
"@testing-library/react": "^14.0.0",
3442
"@testing-library/user-event": "^12.1.10",
3543
"@types/jest": "^27",
44+
"@types/lodash": "^4",
3645
"@types/node": "^20.5.7",
3746
"@types/react": "^18",
3847
"@types/react-dom": "^18",
@@ -100,4 +109,4 @@
100109
]
101110
},
102111
"packageManager": "[email protected]"
103-
}
112+
}

src/.DS_Store

6 KB
Binary file not shown.

src/assets/logo.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/components/.DS_Store

6 KB
Binary file not shown.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { ComingSoon } from "./";
2+
import type { Meta, StoryObj } from "@storybook/react";
3+
4+
const meta: Meta<typeof ComingSoon> = {
5+
title: "Components/Coming Soon",
6+
component: ComingSoon,
7+
};
8+
9+
type Story = StoryObj<typeof ComingSoon>;
10+
11+
export const Default: Story = {};
12+
13+
export const CustomTitle: Story = {
14+
args: {
15+
title: "Custom Title",
16+
},
17+
};
18+
19+
export const CustomDetail: Story = {
20+
args: {
21+
...CustomTitle.args,
22+
detail: "Custom Detail",
23+
},
24+
};
25+
26+
export default meta;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React, { useMemo } from "react";
2+
import { StyleSheet, Text, View } from "react-native";
3+
import { useTheme } from "@react-navigation/native";
4+
import strings from "@/constants/strings";
5+
6+
export interface ComingSoonProps {
7+
title?: string;
8+
detail?: string;
9+
}
10+
11+
export const ComingSoon: React.FC<ComingSoonProps> = ({
12+
title = strings.t("comingSoon.title"),
13+
detail = strings.t("comingSoon.detail"),
14+
}) => {
15+
const { colors } = useTheme();
16+
const styles = useMemo(() => makeStyles(colors), [colors]);
17+
18+
return (
19+
<View style={styles.container}>
20+
<Text style={styles.title}>{title}</Text>
21+
<Text style={styles.detail}>{detail}</Text>
22+
</View>
23+
);
24+
};
25+
26+
const makeStyles = (colors: Record<string, string>) =>
27+
StyleSheet.create({
28+
container: {
29+
backgroundColor: colors.background,
30+
padding: 28,
31+
},
32+
title: {
33+
color: colors.text,
34+
fontWeight: "bold",
35+
fontSize: 48,
36+
},
37+
detail: {
38+
color: colors.text,
39+
},
40+
});
41+
42+
export default ComingSoon;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { ContactForm } from "./";
2+
import type { Meta, StoryObj } from "@storybook/react";
3+
4+
5+
const meta: Meta<typeof ContactForm> = {
6+
title: "Components/Contact Form",
7+
component: ContactForm,
8+
};
9+
10+
type Story = StoryObj<typeof ContactForm>;
11+
12+
export const Default: Story = {};
13+
14+
export default meta;
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
import React, { useCallback } from "react";
2+
import {
3+
Button,
4+
StyleProp,
5+
StyleSheet,
6+
Text,
7+
TextInput,
8+
View,
9+
ViewStyle,
10+
} from "react-native";
11+
import { capitalize } from "lodash";
12+
import { useForm, Controller } from "react-hook-form";
13+
import strings from "@/constants/strings";
14+
import { useStyles, UseStylesHookOptions } from "@/hooks/useStyles";
15+
16+
export type ContactFormFields = {
17+
name: string;
18+
email: string;
19+
message: string;
20+
};
21+
22+
export interface ContactFormProps extends Partial<ContactFormFields> {
23+
title?: string;
24+
detail?: string;
25+
style?: StyleProp<ViewStyle>;
26+
inputContainerStyle?: StyleProp<ViewStyle>;
27+
onSubmit?: (data: ContactFormFields) => void;
28+
}
29+
30+
export const ContactForm: React.FC<ContactFormProps> = ({
31+
title = null,
32+
detail = null,
33+
name = "",
34+
email = "",
35+
message = "",
36+
style = null,
37+
inputContainerStyle = null,
38+
onSubmit = () => {},
39+
}) => {
40+
const styles = useStyles(makeStyles);
41+
42+
const {
43+
control,
44+
formState: { errors },
45+
handleSubmit,
46+
reset,
47+
} = useForm<ContactFormFields>({
48+
defaultValues: {
49+
name,
50+
email,
51+
message,
52+
},
53+
});
54+
55+
const submitCallback = useCallback(
56+
(data: ContactFormFields) => {
57+
onSubmit(data);
58+
reset();
59+
},
60+
[onSubmit, reset]
61+
);
62+
63+
return (
64+
<View style={[styles.container, style]}>
65+
{(title || detail) && (
66+
<View style={styles.textContainer}>
67+
{title && <Text style={styles.titleLabel}>{title}</Text>}
68+
{detail && <Text style={styles.bodyLabel}>{detail}</Text>}
69+
</View>
70+
)}
71+
<View style={styles.formContainer}>
72+
<View style={[styles.inputContainer, inputContainerStyle]}>
73+
<Controller
74+
name="name"
75+
control={control}
76+
rules={{
77+
maxLength: 64,
78+
required: true,
79+
}}
80+
render={({ field: { onChange, onBlur, value } }) => (
81+
<TextInput
82+
style={[styles.nameField, styles.input]}
83+
placeholder={capitalize(
84+
strings.t("contactForm.namePlaceholder")
85+
)}
86+
onBlur={onBlur}
87+
onChangeText={onChange}
88+
value={value}
89+
/>
90+
)}
91+
/>
92+
{errors.name && (
93+
<Text>
94+
{capitalize(
95+
strings.t("contactForm.fieldIsRequired", {
96+
field: strings.t("contactForm.namePlaceholder"),
97+
})
98+
)}
99+
</Text>
100+
)}
101+
102+
<Controller
103+
name="email"
104+
control={control}
105+
rules={{
106+
required: true,
107+
}}
108+
render={({ field: { onChange, onBlur, value } }) => (
109+
<TextInput
110+
style={[styles.emailField, styles.input]}
111+
placeholder={capitalize(
112+
strings.t("contactForm.emailPlaceholder")
113+
)}
114+
onBlur={onBlur}
115+
onChangeText={onChange}
116+
value={value}
117+
/>
118+
)}
119+
/>
120+
{errors.email && (
121+
<Text>
122+
{capitalize(
123+
strings.t("contactForm.fieldIsRequired", {
124+
field: strings.t("contactForm.emailPlaceholder"),
125+
})
126+
)}
127+
</Text>
128+
)}
129+
130+
<Controller
131+
name="message"
132+
control={control}
133+
rules={{ required: true }}
134+
render={({ field: { onChange, onBlur, value } }) => (
135+
<TextInput
136+
multiline
137+
style={[styles.messageField, styles.input]}
138+
placeholder={capitalize(
139+
strings.t("contactForm.messagePlaceholder")
140+
)}
141+
onBlur={onBlur}
142+
onChangeText={onChange}
143+
value={value}
144+
/>
145+
)}
146+
/>
147+
{errors.message && (
148+
<Text>
149+
{capitalize(
150+
strings.t("contactForm.fieldIsRequired", {
151+
field: strings.t("contactForm.messagePlaceholder"),
152+
})
153+
)}
154+
</Text>
155+
)}
156+
</View>
157+
158+
<Button
159+
color={styles.submitButton.backgroundColor}
160+
title={strings.translate("contactForm.submitTitle")}
161+
onPress={handleSubmit(submitCallback)}
162+
/>
163+
</View>
164+
</View>
165+
);
166+
};
167+
168+
const makeStyles: UseStylesHookOptions = (colors) =>
169+
StyleSheet.create({
170+
container: {
171+
rowGap: 28,
172+
},
173+
textContainer: {},
174+
titleLabel: {
175+
color: colors.text,
176+
fontWeight: "bold",
177+
fontSize: 36,
178+
},
179+
bodyLabel: {
180+
color: colors.text,
181+
},
182+
formContainer: {},
183+
inputContainer: {
184+
paddingHorizontal: 20,
185+
paddingBottom: 20,
186+
},
187+
input: {},
188+
nameField: {
189+
color: colors.text,
190+
},
191+
emailField: {
192+
color: colors.text,
193+
},
194+
messageField: {
195+
color: colors.text,
196+
},
197+
submitButton: {
198+
backgroundColor: colors.primary,
199+
},
200+
});
201+
202+
export default ContactForm;

0 commit comments

Comments
 (0)