├── .github
├── CODEOWNERS
└── interface.png
├── src
├── vite-env.d.ts
├── interfaces
│ └── person-data.ts
├── components
│ ├── Input
│ │ ├── primary-input.css
│ │ └── PrimaryInput.tsx
│ └── Modal
│ │ └── modal.tsx
├── index.css
├── hooks
│ └── useIdentityMutation.ts
├── main.tsx
├── App.css
└── App.tsx
├── vite.config.ts
├── tsconfig.node.json
├── .gitignore
├── index.html
├── .eslintrc.cjs
├── tsconfig.json
├── package.json
├── LICENSE
├── public
└── vite.svg
└── README.md
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | @Fernanda-Kipper
--------------------------------------------------------------------------------
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/.github/interface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Fernanda-Kipper/membership-frontend/HEAD/.github/interface.png
--------------------------------------------------------------------------------
/src/interfaces/person-data.ts:
--------------------------------------------------------------------------------
1 | export interface PersonData {
2 | firstName: string,
3 | lastName: string,
4 | email: string
5 | }
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/Input/primary-input.css:
--------------------------------------------------------------------------------
1 | .input-container {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: center;
5 | align-items: center;
6 | }
7 |
8 | .input-container .label {
9 | font-size: 16px;
10 | text-align: start;
11 | width: 100%;
12 | margin-bottom: 8px;
13 | font-weight: 500;
14 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3 | line-height: 1.5;
4 | font-weight: 400;
5 |
6 | color-scheme: light dark;
7 | color: rgba(255, 255, 255, 0.87);
8 | background-color: #242424;
9 |
10 | --border-radius-default: 12px;
11 | }
12 |
13 | * {
14 | padding: 0;
15 | margin: 0;
16 | }
17 |
18 | body {
19 | height: 100vh;
20 | width: 100vw;
21 | }
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: { browser: true, es2020: true },
3 | extends: [
4 | 'eslint:recommended',
5 | 'plugin:@typescript-eslint/recommended',
6 | 'plugin:react-hooks/recommended',
7 | ],
8 | parser: '@typescript-eslint/parser',
9 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
10 | plugins: ['react-refresh'],
11 | rules: {
12 | 'react-refresh/only-export-components': 'warn',
13 | },
14 | }
15 |
--------------------------------------------------------------------------------
/src/hooks/useIdentityMutation.ts:
--------------------------------------------------------------------------------
1 | import { useMutation } from "@tanstack/react-query";
2 | import { PersonData } from "../interfaces/person-data";
3 | import axios from "axios";
4 |
5 | const postData = (data: PersonData) => {
6 | return axios.post("http://localhost:3200/send", data);
7 | }
8 |
9 | export function useIdentityMutation(){
10 | const { mutate, isLoading, isSuccess, isError } = useMutation({
11 | mutationFn: (data: PersonData) => postData(data)
12 | })
13 |
14 | return {
15 | mutate,
16 | isLoading,
17 | isSuccess,
18 | isError
19 | }
20 | }
--------------------------------------------------------------------------------
/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.tsx'
4 | import './index.css'
5 | import { ChakraProvider } from '@chakra-ui/react'
6 | import { QueryClientProvider, QueryClient } from '@tanstack/react-query'
7 |
8 | const queryClient = new QueryClient();
9 |
10 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
11 |
12 |
13 |
14 |
15 |
16 |
17 | ,
18 | )
19 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
5 | "module": "ESNext",
6 | "skipLibCheck": true,
7 |
8 | /* Bundler mode */
9 | "moduleResolution": "bundler",
10 | "allowImportingTsExtensions": true,
11 | "resolveJsonModule": true,
12 | "isolatedModules": true,
13 | "noEmit": true,
14 | "jsx": "react-jsx",
15 |
16 | /* Linting */
17 | "strict": true,
18 | "noUnusedLocals": true,
19 | "noUnusedParameters": true,
20 | "noFallthroughCasesInSwitch": true
21 | },
22 | "include": ["src"],
23 | "references": [{ "path": "./tsconfig.node.json" }]
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/Input/PrimaryInput.tsx:
--------------------------------------------------------------------------------
1 | import { ChangeEventHandler } from "react";
2 | import { Input } from "@chakra-ui/react";
3 |
4 | import "./primary-input.css";
5 |
6 | interface PrimaryInputProps {
7 | name: string,
8 | value: string,
9 | onChange: ChangeEventHandler,
10 | label: string,
11 | placeholder: string
12 | }
13 |
14 | export default function PrimaryInput({ name, value, onChange, label, placeholder } : PrimaryInputProps){
15 | return(
16 |
17 |
18 |
25 |
26 | )
27 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "email-service-frontend",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@chakra-ui/icons": "^2.0.19",
14 | "@chakra-ui/react": "^2.6.0",
15 | "@emotion/react": "^11.10.6",
16 | "@emotion/styled": "^11.10.6",
17 | "@tanstack/react-query": "^4.29.5",
18 | "axios": "^1.4.0",
19 | "framer-motion": "^10.12.4",
20 | "react": "^18.2.0",
21 | "react-dom": "^18.2.0"
22 | },
23 | "devDependencies": {
24 | "@types/react": "^18.0.28",
25 | "@types/react-dom": "^18.0.11",
26 | "@typescript-eslint/eslint-plugin": "^5.57.1",
27 | "@typescript-eslint/parser": "^5.57.1",
28 | "@vitejs/plugin-react": "^4.0.0",
29 | "eslint": "^8.38.0",
30 | "eslint-plugin-react-hooks": "^4.6.0",
31 | "eslint-plugin-react-refresh": "^0.3.4",
32 | "typescript": "^5.0.2",
33 | "vite": "^4.3.2"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2023 Fernanda Kipper Bucoski de Sousa
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Modal/modal.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import { ModalOverlay, ModalBody, ModalCloseButton, ModalHeader, ModalContent, Modal, Heading, Text } from '@chakra-ui/react';
3 | import { CheckCircleIcon } from '@chakra-ui/icons'
4 |
5 | interface ModalProps {
6 | title: string,
7 | subText: string,
8 | isVisible: boolean
9 | }
10 |
11 | export default function SuccessModal({ title, isVisible, subText } : ModalProps){
12 | const [isOpen, setIsOpen] = useState(false);
13 |
14 | const onClose = () => setIsOpen(false);
15 |
16 | useEffect(() => {
17 | if(!isVisible) return;
18 | setIsOpen(true);
19 | }, [isVisible])
20 |
21 | return (
22 |
23 |
24 |
25 |
26 |
27 |
28 |
35 | {title}
36 | {subText}
37 |
38 |
39 |
40 |
41 |
42 | )
43 | }
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | margin: 0 auto;
3 | text-align: center;
4 | }
5 |
6 | .container {
7 | height: 100vh;
8 | width: 100vw;
9 | display: flex;
10 | align-items: center;
11 | justify-content: center;
12 | flex-direction: column;
13 | gap: 24px;
14 | margin: 0 auto;
15 | }
16 |
17 | .container form {
18 | padding: 32px;
19 | box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -2px, rgba(0, 0, 0, 0.3) 0px 3px 7px -3px;
20 | border-radius: var(--border-radius-default);
21 | height: 300px;
22 | width: 100%;
23 | max-width: 80%;
24 | }
25 |
26 | .container form .name-form-container {
27 | display: flex;
28 | align-items: center;
29 | gap: 14px;
30 | }
31 |
32 | .container .product-details {
33 | padding: 24px;
34 | background: linear-gradient(90deg, rgba(225,236,199,1) 0%, rgba(255,237,247,1) 100%);
35 | box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -2px, rgba(0, 0, 0, 0.3) 0px 3px 7px -3px;
36 | border-radius: var(--border-radius-default);
37 | height: 300px;
38 |
39 | width: 100%;
40 | max-width: 80%;
41 | }
42 |
43 | .container .product-details h2 {
44 | text-align: start;
45 | font-size: 32px;
46 | color: #242424;
47 | font-weight: 600;
48 | }
49 |
50 | .container .product-details p {
51 | color: #616161;
52 | text-align: start;
53 | }
54 |
55 | .container .product-details span {
56 | font-weight: 700;
57 | font-size: 32px;
58 | text-align: start;
59 | width: 100%;
60 | color: #3e3e3e;
61 | display: block;
62 | }
63 |
64 | @media(min-width: 768px) {
65 | .container {
66 | flex-direction: row;
67 | padding: 24px;
68 | }
69 |
70 | .container form {
71 | max-width: 50%;
72 | }
73 |
74 | .product-details {
75 | max-width: 50%;
76 | }
77 | }
78 |
79 | @media(min-width: 1080px) {
80 | .container {
81 | flex-direction: row;
82 | padding: 24px;
83 | }
84 |
85 | .container form {
86 | max-width: 600px;
87 | }
88 |
89 | .product-details {
90 | max-width: 600px !important;
91 | }
92 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Email Service Frontend
2 |
3 | 
4 | 
5 |
6 | This repository contains a frontend project built using React JS and Chakra UI. This frontend project interacts with a Node.js API that enables the sending of registration confirmation emails to users, simulating a registration service or newsletter subscription.
7 |
8 |
9 |
10 | ## Features
11 |
12 | - [x] User-friendly interface built with React JS and Chakra UI.
13 | - [x] Integration with a Node.js API for sending registration emails.
14 | - [x] Email validation and confirmation functionality.
15 | - [x] Responsive design for seamless user experience on different devices.
16 |
17 | ## Prerequisites
18 |
19 | To run this project locally, you need to have the following installed:
20 |
21 | - Node.js
22 | - npm (Node Package Manager)
23 |
24 | ## Getting Started
25 |
26 | 1. Clone the repository to your local machine
27 |
28 | ```bash
29 | git clone https://github.com/Fernanda-Kipper/membership-frontend
30 | ```
31 |
32 | 2. Navigate to the project's directory
33 |
34 | ```bash
35 | cd membership-frontend
36 | ```
37 |
38 | 3. Install the dependencies
39 |
40 | ```bash
41 | npm install
42 | ```
43 |
44 | 4. Start the application
45 |
46 | ```bash
47 | npm run dev
48 | ```
49 |
50 | This will launch the application in your default browser at `http://localhost:5173`
51 |
52 | 6. Start the Node.js API
53 |
54 | - Clone the [API repository](https://github.com/Fernanda-Kipper/email-service-backend).
55 | - Follow the instructions in the API's README to start the server.
56 |
57 | ## Contributing
58 |
59 | Contributions are welcome! If you find any issues or have suggestions, please open an issue or submit a pull request in this repository.
60 |
61 | ## License
62 |
63 | This project is licensed under the [MIT License](./LICENSE).
64 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 | import './App.css'
3 | import PrimaryInput from './components/Input/PrimaryInput'
4 | import { Button, Spacer } from '@chakra-ui/react'
5 | import { useIdentityMutation } from './hooks/useIdentityMutation'
6 | import SuccessModal from './components/Modal/modal'
7 |
8 | function App() {
9 | const { mutate, isSuccess } = useIdentityMutation()
10 | const [email, setEmail] = useState("")
11 | const [firstName, setFirstName] = useState("")
12 | const [secondName, setSecondName] = useState("")
13 |
14 | const submit = () => {
15 | mutate({
16 | email,
17 | firstName,
18 | lastName: secondName
19 | })
20 | }
21 |
22 | return (
23 |
24 |
29 |
57 |
58 |
Assinatura Mensal
59 |
60 |
você irá pagar
61 |
R$ 250,00
62 |
63 |
Regras: It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.
64 |
65 |
66 | )
67 | }
68 |
69 | export default App
70 |
--------------------------------------------------------------------------------