├── .cypress.env
├── .dockerignore
├── .env.example
├── .eslintrc
├── .github
├── ISSUE_TEMPLATE
│ ├── bug-report.md
│ └── feature-request.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── test.yml
├── .gitignore
├── .vscode
└── settings.json
├── Dockerfile
├── README.md
├── cypress.json
├── cypress
├── fixtures
│ └── example.json
├── integration
│ └── pages
│ │ ├── Dashboard
│ │ └── index.test.js
│ │ ├── Forgot
│ │ └── index.test.js
│ │ ├── Login
│ │ ├── form_validation.test.js
│ │ └── viewport.test.js
│ │ └── Signup
│ │ └── index.test.js
├── libs
│ └── user.builder.js
├── plugins
│ └── index.js
├── support
│ ├── commands.js
│ └── index.js
└── videos
│ └── pages
│ └── Signup
│ └── index.test.js.mp4
├── docker-compose.yml
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
└── robots.txt
├── readme-files
└── collabcode.png
└── src
├── App.js
├── Router.js
├── components
├── ActionCollab
│ ├── index.js
│ └── styles.js
├── ButtonCollab
│ ├── index.js
│ └── styles.js
├── FieldCollab
│ ├── index.js
│ ├── styles.js
│ └── useFieldCollab.js
├── InputCollab
│ ├── index.js
│ └── styles.js
├── LabelCollab
│ ├── index.js
│ └── styles.js
├── LogoCollab
│ ├── index.js
│ └── styles.js
├── PhotoUserCollab
│ ├── index.js
│ └── styles.js
└── TitleCollab
│ ├── index.js
│ └── styles.js
├── containers
├── ContentAuth
│ ├── index.js
│ └── styles.js
├── FormAuth
│ ├── index.js
│ └── styles.js
├── FormForgot
│ ├── index.js
│ └── validation.js
├── FormLogin
│ ├── index.js
│ └── validation.js
├── FormResendConfirmAccount
│ └── index.js
├── FormSignup
│ ├── index.js
│ └── validation.js
├── HeaderAuth
│ ├── index.js
│ └── styles.js
├── HeaderDashboard
│ ├── index.js
│ └── styles.js
└── PageAuth
│ ├── index.js
│ └── styles.js
├── icons
└── actions
│ ├── visibility.svg
│ └── visibility_off.svg
├── img
├── ball.svg
├── ball_text.svg
├── ball_text_light.svg
├── horizontal.svg
├── horizontal_light.svg
└── userdefault.jpg
├── index.js
├── libs
└── validation
│ ├── email.js
│ ├── index.js
│ ├── minLength.js
│ ├── required.js
│ └── useValidation.js
├── pages
├── Dashboard
│ ├── index.js
│ └── styles.js
├── Forgot
│ └── index.js
├── Login
│ └── index.js
├── ResendConfirmAccount
│ └── index.js
└── Signup
│ ├── index.js
│ └── styles.js
├── services
└── AuthService.js
└── styles
├── elements
└── Base.js
├── generic
└── Reset.js
├── index.js
├── settings
├── Colors.js
├── Gaps.js
└── Radius.js
└── tools
├── Gradients.js
├── Separator.js
├── Shadow.js
└── Typography.js
/.cypress.env:
--------------------------------------------------------------------------------
1 | NODE_ENV=development
2 | PORT=3000
3 |
4 | REACT_APP_API_AUTH=http://auth:3001
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | NODE_ENV=development
2 | PORT=3000
3 |
4 | REACT_APP_API_AUTH=http://localhost:3001
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "extends": [
7 | "plugin:react/recommended",
8 | "airbnb",
9 | "plugin:prettier/recommended"
10 | ],
11 | "globals": {
12 | "Atomics": "readonly",
13 | "SharedArrayBuffer": "readonly"
14 | },
15 | "parserOptions": {
16 | "ecmaFeatures": {
17 | "jsx": true
18 | },
19 | "ecmaVersion": 2018,
20 | "sourceType": "module"
21 | },
22 | "plugins": ["react"],
23 | "rules": {}
24 | }
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ""
5 | labels: bug
6 | assignees: ""
7 | ---
8 |
9 | **Describe the bug**
10 | A clear and concise description of what the bug is.
11 |
12 | **To Reproduce**
13 | Steps to reproduce the behavior:
14 |
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 |
28 | - OS: [e.g. iOS]
29 | - Browser [e.g. chrome, safari]
30 | - Version [e.g. 22]
31 |
32 | **Smartphone (please complete the following information):**
33 |
34 | - Device: [e.g. iPhone6]
35 | - OS: [e.g. iOS8.1]
36 | - Browser [e.g. stock browser, safari]
37 | - Version [e.g. 22]
38 |
39 | **Additional context**
40 | Add any other context about the problem here.
41 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ""
5 | labels: enhancement
6 | assignees: ""
7 | ---
8 |
9 | **Is your feature request related to a problem? Please describe.**
10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11 |
12 | **Describe the solution you'd like**
13 | A clear and concise description of what you want to happen.
14 |
15 | **Describe alternatives you've considered**
16 | A clear and concise description of any alternative solutions or features you've considered.
17 |
18 | **Additional context**
19 | Add any other context or screenshots about the feature request here.
20 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # What's the issue linked?
2 |
3 | Resolve #XX (issue number).
4 |
5 | # Test cases
6 |
7 | Report the test cases that you did in list items:
8 |
9 | - [x] Open page
10 | - [x] Validation name field
11 | - [x] Validation email field
12 | - [x] Send form
13 |
14 | # Did you test this feature on all browsers?
15 |
16 | Yes, tested with all the following browsers:
17 |
18 | - [x] Firefox
19 | - [x] Chrome
20 |
21 | # Description
22 |
23 | Only this is no required, here you add anything that you consider important.
24 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Node.js CI
2 |
3 | on:
4 | pull_request:
5 | branches: [develop]
6 |
7 | pull_request_review:
8 | branches: [develop]
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-18.04
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Test Cypress
17 | uses: actions/setup-node@v1
18 | with:
19 | node-version: "12.x"
20 | - run: npm ci
21 | - run: cp .cypress.env .env
22 | - run: docker-compose up -d
23 | - run: npm run cy:ci
24 | env:
25 | CI: true
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.tabSize": 2,
3 | "editor.formatOnSave": true,
4 | "editor.codeActionsOnSave": {
5 | "source.fixAll.eslint": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | #FROM node:12 as training-frontend
2 | FROM cypress/included:4.3.0 as training-frontend
3 | WORKDIR /app
4 | COPY . ./
5 | RUN npm i --silent
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # CollabCode Training
4 |
5 | An Open Source online course platform. It's the FrontEnd that use React.
6 |
7 | ## Getting Started
8 |
9 | 1. Fork this repo and clone in your machine;
10 |
11 | 2. Change directory to `training-frontend` where you cloned it:
12 |
13 | ```bash
14 | git clone https://github.com/CollabCodeTech/training-frontend
15 | ```
16 |
17 | 3. At the terminal, run:
18 |
19 | ```bash
20 | cd training-frontend
21 | npm i
22 | cp .env.example .env
23 | docker-compose up -d
24 | ```
25 |
26 | 4. Open up [localhost:3000](http://localhost:3000) and start using it
27 |
28 | ### Prerequisites
29 |
30 | - Npm
31 | - Node (>=12.16.1)
32 | - Docker
33 | - Docker compose
34 |
35 | ## Running the tests when you are developing
36 |
37 | ```bash
38 | npm run cy:open
39 | ```
40 |
41 | ## Running all tests
42 |
43 | ```bash
44 | npm test
45 | ```
46 |
47 | ## Built With
48 |
49 | - [ReactJS](http://reactjs.org)
50 |
51 | ## Contributing
52 |
53 | Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us.
54 |
55 | ## Authors
56 |
57 | - **Joviane Jardim** - [@joviane](https://twitter.com/jovianejardim)
58 | - **Marco Bruno** - [@marcobrunobr](https://twitter.com/marcobrunobr)
59 |
60 | See also the list of [contributors](https://github.com/CollabCodeTech/training-frontend/contributors) who participated in this project.
61 |
62 | ## License
63 |
64 | This project is licensed under the MPL 2.0 License - see the [LICENSE](LICENSE.md) file for details
65 |
66 | ## Acknowledgments
67 |
68 | Thanks to all members of CollabCode's community for the support! We love you!
69 |
70 | ## Next Releases
71 |
72 | - [ ] One course and video player (**15 March 2020**) _ashe_
73 | - [ ] Panel to other person that we will invite to send courses (**15 May 2020**) _aphelios_
74 | - [ ] Open panel to community to send courses (**15 July 2020**) _anivia_
75 |
76 | ## Questions
77 |
78 | - [Discord CollabCode](http://bit.ly/discord-collabcode)
79 |
--------------------------------------------------------------------------------
/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "viewportWidth": 1920,
3 | "viewportHeight": 1080,
4 | "baseUrl": "http://localhost:3000",
5 | "video": false,
6 | "defaultCommandTimeout": 8000,
7 | "pageLoadTimeout": 90000,
8 | "numTestsKeptInMemory": 5,
9 | "chromeWebSecurity": false,
10 | "env": {
11 | "RETRIES": 1
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io",
4 | "body": "Fixtures are a great way to mock data for responses to routes"
5 | }
--------------------------------------------------------------------------------
/cypress/integration/pages/Dashboard/index.test.js:
--------------------------------------------------------------------------------
1 | describe("Page Dashboard", function() {
2 | it("Open page on Desktop", function() {
3 | cy.visit("/dashboard");
4 | });
5 |
6 | it("Open page on Mobile", function() {
7 | cy.visit("/dashboard");
8 | cy.viewport("iphone-5");
9 | });
10 |
11 | it("Open page on TV 4K", function() {
12 | cy.visit("/dashboard");
13 | cy.viewport(3840, 2160);
14 | });
15 |
16 | it("Verify if exist header on Web", function() {
17 | cy.visit("/dashboard");
18 |
19 | cy.get("header");
20 | cy.get("header > img");
21 | cy.get("header > div");
22 | });
23 |
24 | it("Verify if exist header on Mobile", function() {
25 | cy.visit("/dashboard");
26 | cy.viewport("iphone-5");
27 |
28 | cy.get("header");
29 | cy.get("header > img");
30 | cy.get("header > div").should("be.not.visible");
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/cypress/integration/pages/Forgot/index.test.js:
--------------------------------------------------------------------------------
1 | describe("Page Forgot", function() {
2 | it("Verify if exist the field E-mail", function() {
3 | cy.visit("/auth/forgot");
4 |
5 | cy.contains("E-mail:");
6 | cy.get("input[name=email]");
7 | });
8 |
9 | it("Send form without filling in the email input", function() {
10 | cy.visit("/auth/forgot");
11 |
12 | cy.contains("Enviar").click();
13 | cy.contains("E-mail é obrigatório");
14 | });
15 |
16 | it("Send form with email invalid", function() {
17 | cy.visit("/auth/forgot");
18 |
19 | cy.get("input[name=email]").type("empix");
20 | cy.contains("Enviar").click();
21 | cy.contains("Preencha com email válido");
22 | });
23 |
24 | it("Send form with email field valid", function() {
25 | cy.visit("/auth/forgot");
26 |
27 | cy.get("input[name=email]").type("any.email@gmail.com");
28 | cy.contains("Enviar").click();
29 |
30 | cy.get("input[name=email] + span").should("not.exist");
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/cypress/integration/pages/Login/form_validation.test.js:
--------------------------------------------------------------------------------
1 | describe("Login form validation", function() {
2 | let $emailField, $passwordField, $submitButton;
3 |
4 | before(function() {
5 | cy.visit("/auth/login");
6 | $emailField = cy.get("label[for=email]");
7 | $passwordField = cy.get("label[for=password]");
8 | $submitButton = cy.get("button[content=Entrar]");
9 | });
10 |
11 | it("Verify if exist the fields: E-mail and Password", function() {
12 | $emailField.contains("E-mail:").get("input[name=email]");
13 | $passwordField.contains("Senha:").get("input[name=password]");
14 | });
15 |
16 | it("Send form without filling in the inputs", function() {
17 | $submitButton.click();
18 |
19 | $emailField.get("span:last-of-type").contains("E-mail é obrigatório");
20 | $passwordField.get("span:last-of-type").contains("Senha é obrigatória");
21 | });
22 |
23 | it("Send form with email invalid", function() {
24 | $emailField.get("input[name=email]").type("santiael");
25 |
26 | $submitButton.click();
27 |
28 | $emailField.get("span:last-of-type").contains("Preencha com email válido");
29 | });
30 |
31 | it("Send form with password invalid", function() {
32 | $passwordField.get("input[name=password]").type("1234567");
33 |
34 | $submitButton.click();
35 | $passwordField
36 | .get("span:last-of-type")
37 | .contains("Senha tem que ter 8 ou mais caracteres");
38 | });
39 |
40 | it("Send form with all fields valid", function() {
41 | $emailField.get("input[name=email]").type("rafaelsantiagods@gmail.com");
42 | $passwordField.get("input[name=password]").type("12345678");
43 |
44 | $submitButton.click();
45 |
46 | $emailField.get("span").should("have.length", 1);
47 | $passwordField.get("span").should("have.length", 1);
48 | });
49 | });
50 |
--------------------------------------------------------------------------------
/cypress/integration/pages/Login/viewport.test.js:
--------------------------------------------------------------------------------
1 | describe("Login page in different screen sizes", function() {
2 | it("Open page on Desktop", function() {
3 | cy.visit("/auth/login");
4 | });
5 |
6 | it("Open page on Mobile", function() {
7 | cy.visit("/auth/login");
8 | cy.viewport("iphone-5");
9 | });
10 |
11 | it("Open page on TV 4K", function() {
12 | cy.visit("/auth/login");
13 | cy.viewport(3840, 2160);
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/cypress/integration/pages/Signup/index.test.js:
--------------------------------------------------------------------------------
1 | import UserBuilder from "../../../libs/user.builder";
2 |
3 | describe("Page Signup", function () {
4 | before(function () {
5 | Cypress.Cookies.debug(true);
6 | });
7 |
8 | it("Open page on Desktop", function () {
9 | cy.visit("/auth/signup");
10 | });
11 |
12 | it("Open page on Mobile", function () {
13 | cy.visit("/auth/signup");
14 | cy.viewport("iphone-5");
15 | });
16 |
17 | it("Open page on TV 4K", function () {
18 | cy.visit("/auth/signup");
19 | cy.viewport(3840, 2160);
20 | });
21 |
22 | it("Verify if exist the fields: Name, E-mail and Password", function () {
23 | cy.visit("/auth/signup");
24 |
25 | cy.contains("Nome:");
26 | cy.get("input[name=name]");
27 |
28 | cy.contains("E-mail:");
29 | cy.get("input[name=email]");
30 |
31 | cy.contains("Senha:");
32 | cy.get("input[name=password]");
33 | });
34 |
35 | it("Send the form without filling in the inputs", function () {
36 | cy.visit("/auth/signup");
37 | cy.contains("Enviar").click();
38 |
39 | cy.contains("Nome é obrigatório");
40 | cy.contains("E-mail é obrigatório");
41 | cy.contains("Senha é obrigatória");
42 | });
43 |
44 | it("Send the form with name invalid that has only one char", function () {
45 | const { name } = UserBuilder.nameInvalid();
46 |
47 | cy.visit("/auth/signup");
48 | cy.get("input[name=name]").type(name);
49 | cy.contains("Enviar").click();
50 | cy.contains("Nome tem que ter 2 ou mais caracteres");
51 | });
52 |
53 | it("Send the form with email invalid", function () {
54 | const { email } = UserBuilder.emailInvalid();
55 |
56 | cy.visit("/auth/signup");
57 | cy.get("input[name=email]").type(email);
58 | cy.contains("Enviar").click();
59 | cy.contains("Preencha com email válido");
60 | });
61 |
62 | it("Send the form with password invalid", function () {
63 | const { password } = UserBuilder.passwordInvalid();
64 |
65 | cy.visit("/auth/signup");
66 | cy.get("input[name=password]").type(password);
67 | cy.contains("Enviar").click();
68 | cy.contains("Senha tem que ter 8 ou mais caracteres");
69 | });
70 |
71 | it("Send the form with the fields name, email and password valid", function () {
72 | const { name, email, password } = UserBuilder.randomUserInfo();
73 |
74 | cy.visit("/auth/signup");
75 | cy.get("input[name=name]").type(name);
76 | cy.get("input[name=email]").type(email);
77 | cy.get("input[name=password]").type(password);
78 | cy.contains("Enviar").click();
79 | cy.location("pathname").should("include", "dashboard");
80 | });
81 |
82 | it("Verify if the cookie jwt was create", function () {
83 | const { name, email, password } = UserBuilder.randomUserInfo();
84 |
85 | cy.clearCookies();
86 | cy.visit("/auth/signup");
87 | cy.get("input[name=name]").type(name);
88 | cy.get("input[name=email]").type(email);
89 | cy.get("input[name=password]").type(password);
90 | cy.contains("Enviar").click();
91 | cy.location("pathname").should("include", "dashboard");
92 | // cy.contains("Dashboard").then(function() {
93 | // cy.getCookie("jwt")
94 | // .should("have.property", "value")
95 | // .and(
96 | // "match",
97 | // /^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*$/
98 | // );
99 | // });
100 | });
101 | });
102 |
--------------------------------------------------------------------------------
/cypress/libs/user.builder.js:
--------------------------------------------------------------------------------
1 | import faker from "faker";
2 |
3 | const generateName = () => {
4 | const firstName = faker.name.firstName();
5 | const lastName = faker.name.lastName();
6 |
7 | return { name: `${firstName} ${lastName}` };
8 | };
9 |
10 | const nameInvalid = () => ({ name: faker.internet.password(1) });
11 | const emailInvalid = () => ({ email: faker.lorem.word() });
12 | const passwordInvalid = () => ({ password: faker.internet.password(7) });
13 | const emailValid = () => ({ email: faker.internet.email() });
14 | const passwordValid = () => ({ password: faker.internet.password() });
15 |
16 | const randomUserInfo = (options = {}) => {
17 | const blank = {};
18 |
19 | return Object.assign(
20 | blank,
21 | {
22 | name: generateName().name,
23 | email: emailValid().email,
24 | password: passwordValid().password
25 | },
26 | { ...options }
27 | );
28 | };
29 |
30 | export default {
31 | generateName,
32 | randomUserInfo,
33 | nameInvalid,
34 | emailInvalid,
35 | passwordInvalid,
36 | emailValid,
37 | passwordValid
38 | };
39 |
--------------------------------------------------------------------------------
/cypress/plugins/index.js:
--------------------------------------------------------------------------------
1 | ///
2 | // ***********************************************************
3 | // This example plugins/index.js can be used to load plugins
4 | //
5 | // You can change the location of this file or turn off loading
6 | // the plugins file with the 'pluginsFile' configuration option.
7 | //
8 | // You can read more here:
9 | // https://on.cypress.io/plugins-guide
10 | // ***********************************************************
11 |
12 | // This function is called when a project is opened or re-opened (e.g. due to
13 | // the project's config changing)
14 |
15 | /**
16 | * @type {Cypress.PluginConfig}
17 | */
18 | module.exports = (on, config) => {
19 | // `on` is used to hook into various events Cypress emits
20 | // `config` is the resolved Cypress config
21 | }
22 |
--------------------------------------------------------------------------------
/cypress/support/commands.js:
--------------------------------------------------------------------------------
1 | // ***********************************************
2 | // This example commands.js shows you how to
3 | // create various custom commands and overwrite
4 | // existing commands.
5 | //
6 | // For more comprehensive examples of custom
7 | // commands please read more here:
8 | // https://on.cypress.io/custom-commands
9 | // ***********************************************
10 | //
11 | //
12 | // -- This is a parent command --
13 | // Cypress.Commands.add("login", (email, password) => { ... })
14 | //
15 | //
16 | // -- This is a child command --
17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
18 | //
19 | //
20 | // -- This is a dual command --
21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
22 | //
23 | //
24 | // -- This will overwrite an existing command --
25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
26 |
--------------------------------------------------------------------------------
/cypress/support/index.js:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/index.js is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import './commands'
18 |
19 | // Alternatively you can use CommonJS syntax:
20 | // require('./commands')
21 |
--------------------------------------------------------------------------------
/cypress/videos/pages/Signup/index.test.js.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CollabCodeTech/training-frontend/c45676c1a567844004a5741ba0c61d822302c7ad/cypress/videos/pages/Signup/index.test.js.mp4
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.7"
2 |
3 | services:
4 | email:
5 | image: collabcode/training-email
6 | container_name: "email"
7 | networks:
8 | - internal
9 |
10 | auth:
11 | image: collabcode/training-auth
12 | container_name: "auth"
13 | environment:
14 | - NODE_ENV
15 | ports:
16 | - "3001:3001"
17 | networks:
18 | - internal
19 | depends_on:
20 | - mongo
21 |
22 | mongo:
23 | image: mongo
24 | container_name: "mongo"
25 | environment:
26 | MONGO_INITDB_ROOT_USERNAME: root
27 | MONGO_INITDB_ROOT_PASSWORD: root
28 | ports:
29 | - "27017:27017"
30 | networks:
31 | - internal
32 |
33 | frontend:
34 | image: "cypress/included:4.3.0"
35 | container_name: "frontend"
36 | ipc: host
37 | environment:
38 | - NODE_ENV=local
39 | - QT_X11_NO_MITSHM=1
40 | - _X11_NO_MITSHM=1
41 | - _MITSHM=0
42 | - ELECTRON_ENABLE_STACK_DUMPING=1
43 | ports:
44 | - "3000:${PORT}"
45 | expose:
46 | - "3000"
47 | working_dir: /app
48 | networks:
49 | - internal
50 | volumes:
51 | - .:/app/
52 | entrypoint: npm start
53 | depends_on:
54 | - auth
55 | - email
56 | networks:
57 | internal:
58 | driver: bridge
59 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "training-frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.4.0",
8 | "@testing-library/user-event": "^7.2.1",
9 | "cypress": "^4.0.1",
10 | "react": "^16.12.0",
11 | "react-dom": "^16.12.0",
12 | "react-router-dom": "^5.1.2",
13 | "react-scripts": "^3.4.0",
14 | "styled-components": "^5.0.0",
15 | "superagent": "^5.2.1"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "cypress run",
21 | "eject": "react-scripts eject",
22 | "cy:open": "cypress open",
23 | "cy:ci": "docker exec frontend cypress run"
24 | },
25 | "eslintConfig": {
26 | "extends": "react-app"
27 | },
28 | "browserslist": {
29 | "production": [
30 | ">0.2%",
31 | "not dead",
32 | "not op_mini all"
33 | ],
34 | "development": [
35 | "last 1 chrome version",
36 | "last 1 firefox version",
37 | "last 1 safari version"
38 | ]
39 | },
40 | "devDependencies": {
41 | "cypress-plugin-retries": "^1.5.2",
42 | "eslint": "^6.8.0",
43 | "eslint-config-airbnb": "^18.0.1",
44 | "eslint-config-prettier": "^6.10.0",
45 | "eslint-plugin-import": "^2.20.1",
46 | "eslint-plugin-jsx-a11y": "^6.2.3",
47 | "eslint-plugin-prettier": "^3.1.2",
48 | "eslint-plugin-react": "^7.18.3",
49 | "eslint-plugin-react-hooks": "^1.7.0",
50 | "faker": "^4.1.0"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CollabCodeTech/training-frontend/c45676c1a567844004a5741ba0c61d822302c7ad/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 |
28 |
32 |
33 | CollabCode Training
34 |
35 |
36 |
37 |
38 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/readme-files/collabcode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CollabCodeTech/training-frontend/c45676c1a567844004a5741ba0c61d822302c7ad/readme-files/collabcode.png
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Styles from "./styles";
4 | import Router from "./Router";
5 |
6 | export default function App() {
7 | return (
8 | <>
9 |
10 |
11 |
12 | >
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/src/Router.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { BrowserRouter as Routes, Switch, Route } from "react-router-dom";
3 |
4 | import Login from "./pages/Login";
5 | import Signup from "./pages/Signup";
6 | import Forgot from "./pages/Forgot";
7 | import ResendConfirmAccount from "./pages/ResendConfirmAccount";
8 |
9 | import Dashboard from "./pages/Dashboard";
10 |
11 | function Router() {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
24 |
25 |
26 | );
27 | }
28 |
29 | export default Router;
30 |
--------------------------------------------------------------------------------
/src/components/ActionCollab/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Action } from "./styles";
4 |
5 | function ActionCollab(props) {
6 | return {props.content};
7 | }
8 |
9 | export default ActionCollab;
10 |
--------------------------------------------------------------------------------
/src/components/ActionCollab/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | import { Link } from "react-router-dom";
4 | import { _body1 } from "../../styles/tools/Typography";
5 |
6 | export const Action = styled(Link)`
7 | ${_body1};
8 | text-decoration: none;
9 | color: var(--color-floral-white);
10 |
11 | &:hover,
12 | &:focus {
13 | color: var(--color-peach);
14 | }
15 | `;
16 |
--------------------------------------------------------------------------------
/src/components/ButtonCollab/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Button, Content } from "./styles";
3 |
4 | function ButtonCollab(props) {
5 | return (
6 |
9 | );
10 | }
11 |
12 | export default ButtonCollab;
13 |
--------------------------------------------------------------------------------
/src/components/ButtonCollab/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 | import { Link } from "react-router-dom";
3 |
4 | import { _h6 } from "../../styles/tools/Typography";
5 |
6 | export const Button = styled(Link).attrs({ as: "button" })`
7 | ${_h6};
8 | cursor: pointer;
9 | display: flex;
10 | align-items: center;
11 | justify-content: center;
12 | position: relative;
13 | text-decoration: none;
14 | border: none;
15 | border-radius: var(--radius-big);
16 | background-color: var(--color-fiery-rose);
17 | color: var(--color-floral-white);
18 | opacity: 0.9;
19 | transition: opacity 100ms linear, transform 50ms linear;
20 | z-index: 1;
21 |
22 | &:hover,
23 | &:focus {
24 | opacity: 1;
25 | }
26 |
27 | &:active {
28 | transform: translateY(2px);
29 | }
30 | `;
31 |
32 | export const Content = styled.span``;
33 |
--------------------------------------------------------------------------------
/src/components/FieldCollab/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import iconVisibilityOff from "../../icons/actions/visibility_off.svg";
3 | import iconVisibility from "../../icons/actions/visibility.svg";
4 | import LabelCollab from "../LabelCollab";
5 | import InputCollab from "../InputCollab";
6 | import useFieldCollab from "./useFieldCollab";
7 | import { Content, Icon, Error } from "./styles";
8 |
9 | const FieldCollab = ({
10 | content,
11 | id,
12 | name,
13 | value,
14 | htmlFor,
15 | type = "text",
16 | msgError,
17 | onChange
18 | }) => {
19 | const { show, showPassword } = useFieldCollab();
20 |
21 | function showIconVisibility(type) {
22 | if (type === "password") {
23 | return (
24 |
28 | );
29 | }
30 | }
31 |
32 | function showError(msgError) {
33 | return msgError && {msgError};
34 | }
35 |
36 | function defineType(type) {
37 | if (type === "password" && !show) {
38 | return "password";
39 | } else if (type === "password" && show) {
40 | return "text";
41 | }
42 | return type;
43 | }
44 |
45 | return (
46 |
47 | {content}
48 |
55 | {showIconVisibility(type)}
56 | {showError(msgError)}
57 |
58 | );
59 | };
60 |
61 | export default FieldCollab;
62 |
--------------------------------------------------------------------------------
/src/components/FieldCollab/styles.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import { _caption } from '../../styles/tools/Typography';
3 |
4 | export const Content = styled.span`
5 | display: block;
6 | margin-bottom: var(--gap-smaller);
7 | `;
8 |
9 | export const Icon = styled.img`
10 | position: absolute;
11 | bottom: var(--gap-smaller);
12 | right: var(--gap-smaller);
13 | overflow: hidden;
14 | width: 30px;
15 | transition: transform 100ms linear;
16 | cursor: pointer;
17 |
18 | &:hover {
19 | transform: scale(1.1);
20 | }
21 | `;
22 |
23 | export const Error = styled.span`
24 | ${_caption};
25 | color: var(--color-sandstorm);
26 | position: absolute;
27 | bottom: 0;
28 | left: 0;
29 | transform: translateY(100%);
30 | `;
31 |
--------------------------------------------------------------------------------
/src/components/FieldCollab/useFieldCollab.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | function useFieldCollab() {
4 | const [show, setShow] = useState(false);
5 |
6 | function showPassword() {
7 | setShow(old => !old);
8 | }
9 |
10 | return {
11 | show,
12 | showPassword
13 | };
14 | }
15 |
16 | export default useFieldCollab;
17 |
--------------------------------------------------------------------------------
/src/components/InputCollab/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Input } from "./styles";
4 |
5 | function InputCollab(props) {
6 | return ;
7 | }
8 |
9 | export default InputCollab;
10 |
--------------------------------------------------------------------------------
/src/components/InputCollab/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | import { _h6 } from "../../styles/tools/Typography";
4 |
5 | export const Input = styled.input`
6 | --widthIcon: 24px;
7 | ${_h6};
8 | box-sizing: border-box;
9 | color: var(--color-platinum);
10 | background-color: transparent;
11 | width: 100%;
12 | border: none;
13 | outline: none;
14 | border-bottom: 1px solid var(--color-floral-white);
15 | padding: var(--gap-smaller) calc(var(--widthIcon) + var(--gap-smaller) * 2)
16 | var(--gap-smaller) 0;
17 |
18 | &:hover,
19 | &:focus {
20 | border-bottom-color: var(--color-peach);
21 | border-bottom-witth: 2px;
22 | }
23 | `;
24 |
--------------------------------------------------------------------------------
/src/components/LabelCollab/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Label } from "./styles";
4 |
5 | function LabelCollab({ htmlFor, children, content, warning = false }) {
6 | return (
7 |
10 | );
11 | }
12 |
13 | export default LabelCollab;
14 |
--------------------------------------------------------------------------------
/src/components/LabelCollab/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | import { _h6 } from "../../styles/tools/Typography";
4 |
5 | export const Label = styled.label`
6 | ${_h6};
7 | color: ${({ warning }) =>
8 | warning ? "var(--color-sandstorm)" : "var(--color-floral-white)"};
9 | position: relative;
10 | display: block;
11 |
12 | &:hover {
13 | color: var(--color-peach);
14 | }
15 | `;
16 |
--------------------------------------------------------------------------------
/src/components/LogoCollab/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Logo } from "./styles";
4 |
5 | import ball from "../../img/ball.svg";
6 | import ballText from "../../img/ball_text.svg";
7 | import ballTextLight from "../../img/ball_text_light.svg";
8 | import horizontal from "../../img/horizontal.svg";
9 | import horizontalLight from "../../img/horizontal_light.svg";
10 |
11 | const LogoCollab = function({ type = "horizontal" }) {
12 | const types = { ball, ballText, ballTextLight, horizontal, horizontalLight };
13 |
14 | return ;
15 | };
16 |
17 | export default LogoCollab;
18 |
--------------------------------------------------------------------------------
/src/components/LogoCollab/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const Logo = styled.img``;
4 |
--------------------------------------------------------------------------------
/src/components/PhotoUserCollab/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Container, PhotoUser } from "./styles";
4 | import ImageUserDefault from "../../img/userdefault.jpg";
5 |
6 | const PhotoUserCollab = ({ img }) => (
7 |
8 |
9 |
10 | );
11 |
12 | export default PhotoUserCollab;
13 |
--------------------------------------------------------------------------------
/src/components/PhotoUserCollab/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const Container = styled.div`
4 | height: 40px;
5 | width: 40px;
6 | border-radius: 50%;
7 | vertical-align: top;
8 | justify-content: center;
9 | align-items: center;
10 | overflow: hidden;
11 | text-decoration: none;
12 | border: 0;
13 | margin: 10px;
14 | position: relative;
15 |
16 | @media (max-width: 767.98px) {
17 | display: none;
18 | }
19 | `;
20 |
21 | export const PhotoUser = styled.img`
22 | margin: 0;
23 | position: absolute;
24 | top: 50%;
25 | left: 50%;
26 | margin-right: -50%;
27 | transform: translate(-50%, -50%)
28 | `;
29 |
--------------------------------------------------------------------------------
/src/components/TitleCollab/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Title } from "./styles";
4 |
5 | function TitleCollab({ content }) {
6 | return {content};
7 | }
8 |
9 | export default TitleCollab;
10 |
--------------------------------------------------------------------------------
/src/components/TitleCollab/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | import { _h5 } from "../../styles/tools/Typography";
4 |
5 | export const Title = styled.h1`
6 | ${_h5};
7 | color: var(--color-floral-white);
8 | `;
9 |
--------------------------------------------------------------------------------
/src/containers/ContentAuth/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Content } from "./styles";
4 |
5 | function ContentAuth({ children }) {
6 | return {children};
7 | }
8 |
9 | export default ContentAuth;
10 |
--------------------------------------------------------------------------------
/src/containers/ContentAuth/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const Content = styled.div`
4 | width: 400px;
5 |
6 | @media (min-height: 570px) {
7 | height: auto;
8 | }
9 |
10 | @media (min-width: 1596px) and (min-height: 900px) {
11 | display: flex;
12 | width: 1596px;
13 | height: 900px;
14 | overflow: hidden;
15 | background-color: var(--color-arsenic);
16 | }
17 |
18 | @media (min-width: 1920px) and (min-height: 1080px) {
19 | width: 75%;
20 | height: 80%;
21 | }
22 | `;
23 |
--------------------------------------------------------------------------------
/src/containers/FormAuth/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Form } from "./styles";
4 |
5 | function FormAuth(props) {
6 | return ;
7 | }
8 |
9 | export default FormAuth;
10 |
--------------------------------------------------------------------------------
/src/containers/FormAuth/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | import { _shadowBottom } from "../../styles/tools/Shadow";
4 | import { Title } from "../../components/TitleCollab/styles";
5 | import { Label } from "../../components/LabelCollab/styles";
6 | import { Button } from "../../components/ButtonCollab/styles";
7 | import { Action } from "../../components/ActionCollab/styles";
8 | import { _h4 } from "../../styles/tools/Typography";
9 |
10 | export const Form = styled.form`
11 | box-sizing: border-box;
12 | padding: 0 var(--gap-small) var(--gap-medium);
13 |
14 | & > ${Title} {
15 | text-align: center;
16 | margin-bottom: var(--gap-bigger);
17 | }
18 |
19 | & > ${Label}:not(:last-of-type) {
20 | display: block;
21 | margin-bottom: var(--gap-big);
22 | }
23 |
24 | & > ${Button} {
25 | ${_shadowBottom};
26 | width: 100%;
27 | height: 42px;
28 | margin-top: var(--gap-bigger);
29 | }
30 |
31 | & > ${Action} {
32 | display: block;
33 | text-align: center;
34 | margin-top: var(--gap-small);
35 |
36 | &:active {
37 | box-sizing: none;
38 | }
39 | }
40 |
41 | @media (min-width: 1596px) and (min-height: 900px) {
42 | box-sizing: border-box;
43 | width: 60%;
44 | padding-left: 18%;
45 | padding-right: 5%;
46 | display: flex;
47 | flex-direction: column;
48 | justify-content: center;
49 |
50 | & > ${Title} {
51 | ${_h4};
52 | margin-bottom: calc(var(--gap-bigger) * 2);
53 | }
54 |
55 | & > ${Label}:not(:last-of-type) {
56 | margin-bottom: var(--gap-bigger);
57 | }
58 |
59 | & > ${Button} {
60 | height: 50px;
61 | margin-top: calc(var(--gap-bigger) + var(--gap-medium));
62 | }
63 | }
64 | `;
65 |
--------------------------------------------------------------------------------
/src/containers/FormForgot/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import TitleCollab from "../../components/TitleCollab";
4 | import FieldCollab from "../../components/FieldCollab";
5 | import ButtonCollab from "../../components/ButtonCollab";
6 |
7 | import FormAuth from "../../containers/FormAuth";
8 | import LabelCollab from "../../components/LabelCollab";
9 |
10 | import useValidation from "../../libs/validation/useValidation";
11 | import validation from "./validation";
12 |
13 | function FormForgot() {
14 | const { value, handleChange, handleSubmit, errors } = useValidation(
15 | validation,
16 | sendFormForgot,
17 | "email"
18 | );
19 |
20 | function sendFormForgot() {}
21 |
22 | return (
23 |
24 |
25 |
26 |
30 |
31 |
40 |
41 |
42 |
43 | );
44 | }
45 |
46 | export default FormForgot;
47 |
--------------------------------------------------------------------------------
/src/containers/FormForgot/validation.js:
--------------------------------------------------------------------------------
1 | import { required, isEmail } from "../../libs/validation";
2 |
3 | function validation(values) {
4 | const { email } = values;
5 | let errors = {};
6 |
7 | errors.email =
8 | required(email, "E-mail é obrigatório") ||
9 | isEmail(email, "Preencha com email válido");
10 |
11 | return errors;
12 | }
13 |
14 | export default validation;
15 |
--------------------------------------------------------------------------------
/src/containers/FormLogin/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import TitleCollab from "../../components/TitleCollab";
4 | import FieldCollab from "../../components/FieldCollab";
5 | import ButtonCollab from "../../components/ButtonCollab";
6 | import ActionCollab from "../../components/ActionCollab";
7 |
8 | import FormAuth from "../../containers/FormAuth";
9 |
10 | import useValidation from "../../libs/validation/useValidation";
11 | import validation from "./validation";
12 |
13 | function FormLogin() {
14 | const { value, handleChange, handleSubmit, errors } = useValidation(
15 | validation,
16 | signIn,
17 | "email",
18 | "password"
19 | );
20 |
21 | function signIn() {}
22 |
23 | return (
24 |
25 |
26 |
27 |
36 |
37 |
47 |
48 |
49 |
50 |
51 |
52 | );
53 | }
54 |
55 | export default FormLogin;
56 |
--------------------------------------------------------------------------------
/src/containers/FormLogin/validation.js:
--------------------------------------------------------------------------------
1 | import { required, isEmail, minLength } from "../../libs/validation";
2 |
3 | function validation(values) {
4 | const { email, password } = values;
5 | let errors = {};
6 |
7 | errors.email =
8 | required(email, "E-mail é obrigatório") ||
9 | isEmail(email, "Preencha com email válido");
10 |
11 | errors.password =
12 | required(password, "Senha é obrigatória") ||
13 | minLength(8, password, "Senha tem que ter 8 ou mais caracteres");
14 |
15 | return errors;
16 | }
17 |
18 | export default validation;
19 |
--------------------------------------------------------------------------------
/src/containers/FormResendConfirmAccount/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import TitleCollab from "../../components/TitleCollab";
4 | import FieldCollab from "../../components/FieldCollab";
5 | import ButtonCollab from "../../components/ButtonCollab";
6 |
7 | import FormAuth from "../FormAuth";
8 | import LabelCollab from "../../components/LabelCollab";
9 |
10 | function FormResendConfirmAccount() {
11 | return (
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 | );
25 | }
26 |
27 | export default FormResendConfirmAccount;
28 |
--------------------------------------------------------------------------------
/src/containers/FormSignup/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useHistory } from "react-router-dom";
3 |
4 | import TitleCollab from "../../components/TitleCollab";
5 | import FieldCollab from "../../components/FieldCollab";
6 | import ButtonCollab from "../../components/ButtonCollab";
7 | import ActionCollab from "../../components/ActionCollab";
8 | import FormAuth from "../../containers/FormAuth";
9 | import useValidation from "../../libs/validation/useValidation";
10 | import validation from "./validation";
11 | import AuthService from "../../services/AuthService";
12 |
13 | function FormLogin() {
14 | const {
15 | value,
16 | handleChange,
17 | handleSubmit,
18 | errors,
19 | setErrors
20 | } = useValidation(validation, sendUser, "name", "email", "password");
21 | const history = useHistory();
22 |
23 | function sendUser() {
24 | AuthService.signup(value)
25 | .withCredentials()
26 | .then(function() {
27 | history.replace("/dashboard");
28 | })
29 | .catch(function({ response }) {
30 | const { field, error } = response.body[0];
31 | setErrors({ [field]: error });
32 | });
33 | }
34 |
35 | return (
36 |
37 |
38 |
39 |
48 |
49 |
58 |
59 |
69 |
70 |
71 |
72 |
73 | );
74 | }
75 |
76 | export default FormLogin;
77 |
--------------------------------------------------------------------------------
/src/containers/FormSignup/validation.js:
--------------------------------------------------------------------------------
1 | import { required, isEmail, minLength } from "../../libs/validation";
2 |
3 | function validation(values) {
4 | const { name, email, password } = values;
5 | let errors = {};
6 |
7 | errors.name =
8 | required(name, "Nome é obrigatório") ||
9 | minLength(2, name, "Nome tem que ter 2 ou mais caracteres");
10 |
11 | errors.email =
12 | required(email, "E-mail é obrigatório") ||
13 | isEmail(email, "Preencha com email válido");
14 |
15 | errors.password =
16 | required(password, "Senha é obrigatória") ||
17 | minLength(8, password, "Senha tem que ter 8 ou mais caracteres");
18 |
19 | return errors;
20 | }
21 |
22 | export default validation;
23 |
--------------------------------------------------------------------------------
/src/containers/HeaderAuth/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import LogoCollab from "../../components/LogoCollab";
4 |
5 | import { Header } from "./styles";
6 |
7 | function HeaderLogin() {
8 | return (
9 |
12 | );
13 | }
14 |
15 | export default HeaderLogin;
16 |
--------------------------------------------------------------------------------
/src/containers/HeaderAuth/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | import { Logo } from "../../components/LogoCollab/styles.js";
4 |
5 | export const Header = styled.header`
6 | margin-bottom: var(--gap-big);
7 | text-align: center;
8 |
9 | ${Logo} {
10 | height: 120px;
11 | }
12 |
13 | @media (min-width: 1596px) and (min-height: 900px) {
14 | position: relative;
15 | width: 40%;
16 | height: 100%;
17 | background-color: var(--color-floral-white);
18 |
19 | &::after {
20 | content: "";
21 | position: absolute;
22 | top: 0;
23 | right: 0;
24 | height: 110%;
25 | width: 30%;
26 | background-color: var(--color-floral-white);
27 | z-index: 0;
28 | transform: translateX(50%) rotate(10deg) translateY(-5%);
29 | }
30 |
31 | ${Logo} {
32 | height: 80%;
33 | position: absolute;
34 | z-index: 1;
35 | padding: 0;
36 | margin: 0;
37 | transform: translateX(-25%);
38 | }
39 | }
40 | `;
41 |
--------------------------------------------------------------------------------
/src/containers/HeaderDashboard/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import LogoCollab from "../../components/LogoCollab";
4 | import PhotoUserCollab from "../../components/PhotoUserCollab";
5 |
6 | import { Header } from "./styles";
7 |
8 | export default function HeaderDashboard() {
9 | return (
10 |
14 | );
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/src/containers/HeaderDashboard/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const Header = styled.header`
4 | display: flex;
5 | justify-content: space-between;
6 | align-items: center;
7 |
8 | padding: 10px 20px;
9 |
10 | img {
11 | height: 40px;
12 | }
13 |
14 | @media (max-width: 767.98px) {
15 | justify-content: center;
16 | }
17 | `;
18 |
--------------------------------------------------------------------------------
/src/containers/PageAuth/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Page } from "./styles";
4 |
5 | function PageAuth({ children }) {
6 | return {children};
7 | }
8 |
9 | export default PageAuth;
10 |
--------------------------------------------------------------------------------
/src/containers/PageAuth/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const Page = styled.main`
4 | display: flex;
5 | align-items: center;
6 | justify-content: center;
7 | padding-top: var(--gap-medium);
8 |
9 | @media (min-height: 570px) {
10 | height: 100vh;
11 | }
12 |
13 | @media (min-width: 1596px) and (min-height: 900px) {
14 | padding: 0;
15 | }
16 | `;
17 |
--------------------------------------------------------------------------------
/src/icons/actions/visibility.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/icons/actions/visibility_off.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/img/ball.svg:
--------------------------------------------------------------------------------
1 |
173 |
--------------------------------------------------------------------------------
/src/img/ball_text.svg:
--------------------------------------------------------------------------------
1 |
257 |
--------------------------------------------------------------------------------
/src/img/ball_text_light.svg:
--------------------------------------------------------------------------------
1 |
23 |
--------------------------------------------------------------------------------
/src/img/horizontal.svg:
--------------------------------------------------------------------------------
1 |
235 |
--------------------------------------------------------------------------------
/src/img/horizontal_light.svg:
--------------------------------------------------------------------------------
1 |
237 |
--------------------------------------------------------------------------------
/src/img/userdefault.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CollabCodeTech/training-frontend/c45676c1a567844004a5741ba0c61d822302c7ad/src/img/userdefault.jpg
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import App from "./App";
4 |
5 | ReactDOM.render(, document.getElementById("root"));
6 |
--------------------------------------------------------------------------------
/src/libs/validation/email.js:
--------------------------------------------------------------------------------
1 | function isEmail(value, msgError) {
2 | return !/\S+@\S+\.\S+/.test(value) && msgError;
3 | }
4 |
5 | export default isEmail;
6 |
--------------------------------------------------------------------------------
/src/libs/validation/index.js:
--------------------------------------------------------------------------------
1 | import required from "./required";
2 | import isEmail from "./email";
3 | import minLength from "./minLength";
4 |
5 | export { required, isEmail, minLength };
6 |
--------------------------------------------------------------------------------
/src/libs/validation/minLength.js:
--------------------------------------------------------------------------------
1 | function minLength(length, value, msgError) {
2 | return value.length < length && msgError;
3 | }
4 |
5 | export default minLength;
6 |
--------------------------------------------------------------------------------
/src/libs/validation/required.js:
--------------------------------------------------------------------------------
1 | function required(value, msgError) {
2 | return !value && msgError;
3 | }
4 |
5 | export default required;
6 |
--------------------------------------------------------------------------------
/src/libs/validation/useValidation.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 |
3 | function useValidation(validation = false, callback, ...values) {
4 | const [value, setValue] = useState(
5 | Object.assign(...values.map(value => ({ [value]: "" })))
6 | );
7 | const [errors, setErrors] = useState({});
8 | const [isSubmitting, setIsSubmitting] = useState(false);
9 |
10 | function handleChange({ target }) {
11 | const { name, value, type, checked } = target;
12 |
13 | setValue(oldValue => {
14 | const newValue =
15 | type === "checkbox" ? { [name]: checked } : { [name]: value };
16 |
17 | return Object.assign({ ...oldValue }, newValue);
18 | });
19 | }
20 |
21 | function handleSubmit(event) {
22 | event.preventDefault();
23 |
24 | setErrors(validation instanceof Object ? validation(value) : {});
25 | setIsSubmitting(true);
26 | }
27 |
28 | function sendFormIsValid() {
29 | if (
30 | Object.values(errors).filter(error => error).length === 0 &&
31 | isSubmitting
32 | ) {
33 | callback();
34 | }
35 | }
36 |
37 | useEffect(sendFormIsValid, [errors]);
38 |
39 | return { value, setValue, handleChange, handleSubmit, errors, setErrors };
40 | }
41 |
42 | export default useValidation;
43 |
--------------------------------------------------------------------------------
/src/pages/Dashboard/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import HeaderDashboard from "../../containers/HeaderDashboard";
4 | import { SectionFake } from "./styles";
5 |
6 | function Dashboard() {
7 | return (
8 | <>
9 |
10 |
11 | >
12 | );
13 | }
14 |
15 | export default Dashboard;
16 |
--------------------------------------------------------------------------------
/src/pages/Dashboard/styles.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 | import { _separator } from "../../styles/tools/Separator";
3 |
4 | export const SectionFake = styled.section`
5 | height: 300px;
6 | ${_separator};
7 | `;
8 |
--------------------------------------------------------------------------------
/src/pages/Forgot/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import PageAuth from "../../containers/PageAuth";
4 | import ContentAuth from "../../containers/ContentAuth";
5 | import HeaderAuth from "../../containers/HeaderAuth";
6 | import FormForgot from "../../containers/FormForgot";
7 |
8 | function Forgot() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
19 | export default Forgot;
20 |
--------------------------------------------------------------------------------
/src/pages/Login/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import PageAuth from "../../containers/PageAuth";
4 | import ContentAuth from "../../containers/ContentAuth";
5 | import HeaderAuth from "../../containers/HeaderAuth";
6 | import FormLogin from "../../containers/FormLogin";
7 |
8 | function Login() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
19 | export default Login;
20 |
--------------------------------------------------------------------------------
/src/pages/ResendConfirmAccount/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import PageAuth from "../../containers/PageAuth";
4 | import ContentAuth from "../../containers/ContentAuth";
5 | import HeaderAuth from "../../containers/HeaderAuth";
6 | import FormResendConfirmAccount from "../../containers/FormResendConfirmAccount";
7 |
8 | function ResendConfirmAccount() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
19 | export default ResendConfirmAccount;
20 |
--------------------------------------------------------------------------------
/src/pages/Signup/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import PageAuth from "../../containers/PageAuth";
4 | import ContentAuth from "../../containers/ContentAuth";
5 | import HeaderAuth from "../../containers/HeaderAuth";
6 | import FormSignup from "../../containers/FormSignup";
7 |
8 | function Signup() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
19 | export default Signup;
20 |
--------------------------------------------------------------------------------
/src/pages/Signup/styles.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CollabCodeTech/training-frontend/c45676c1a567844004a5741ba0c61d822302c7ad/src/pages/Signup/styles.js
--------------------------------------------------------------------------------
/src/services/AuthService.js:
--------------------------------------------------------------------------------
1 | import request from "superagent";
2 |
3 | function signup(user) {
4 | const { REACT_APP_API_AUTH } = process.env;
5 |
6 | return request
7 | .post(`${REACT_APP_API_AUTH}/api/user`)
8 | .set("Content-Type", "application/json")
9 | .send(user);
10 | }
11 |
12 | export default { signup };
13 |
--------------------------------------------------------------------------------
/src/styles/elements/Base.js:
--------------------------------------------------------------------------------
1 | import { createGlobalStyle } from "styled-components";
2 |
3 | import { _gradientBg } from "../tools/Gradients";
4 |
5 | const Base = createGlobalStyle`
6 | body {
7 | ${_gradientBg}
8 | height: 100vh;
9 | font-family: 'Comfortaa', sans-serif;
10 | line-height: 1.5em;
11 | }
12 | `;
13 |
14 | export default Base;
15 |
--------------------------------------------------------------------------------
/src/styles/generic/Reset.js:
--------------------------------------------------------------------------------
1 | import { createGlobalStyle } from "styled-components";
2 |
3 | const Reset = createGlobalStyle`
4 | /* http://meyerweb.com/eric/tools/css/reset/
5 | v2.0 | 20110126
6 | License: none (public domain)
7 | */
8 |
9 | html, body, div, span, applet, object, iframe,
10 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
11 | a, abbr, acronym, address, big, cite, code,
12 | del, dfn, em, img, ins, kbd, q, s, samp,
13 | small, strike, strong, sub, sup, tt, var,
14 | b, u, i, center,
15 | dl, dt, dd, ol, ul, li,
16 | fieldset, form, label, legend,
17 | table, caption, tbody, tfoot, thead, tr, th, td,
18 | article, aside, canvas, details, embed,
19 | figure, figcaption, footer, header, hgroup,
20 | menu, nav, output, ruby, section, summary,
21 | time, mark, audio, video {
22 | margin: 0;
23 | padding: 0;
24 | border: 0;
25 | font-size: 100%;
26 | font: inherit;
27 | vertical-align: baseline;
28 | }
29 | /* HTML5 display-role reset for older browsers */
30 | article, aside, details, figcaption, figure,
31 | footer, header, hgroup, menu, nav, section {
32 | display: block;
33 | }
34 | body {
35 | line-height: 1;
36 | }
37 | ol, ul {
38 | list-style: none;
39 | }
40 | blockquote, q {
41 | quotes: none;
42 | }
43 | blockquote:before, blockquote:after,
44 | q:before, q:after {
45 | content: '';
46 | content: none;
47 | }
48 | table {
49 | border-collapse: collapse;
50 | border-spacing: 0;
51 | }
52 | input, button {
53 | font: inherit;
54 | }
55 | html,body {
56 | height: 100%;
57 | }
58 | `;
59 |
60 | export default Reset;
61 |
--------------------------------------------------------------------------------
/src/styles/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Colors from "./settings/Colors";
4 | import Gaps from "./settings/Gaps";
5 | import Radius from "./settings/Radius";
6 | import Reset from "./generic/Reset";
7 | import Base from "./elements/Base";
8 |
9 | const Styles = () => (
10 | <>
11 |
12 |
13 |
14 |
15 |
16 | >
17 | );
18 |
19 | export default Styles;
20 |
--------------------------------------------------------------------------------
/src/styles/settings/Colors.js:
--------------------------------------------------------------------------------
1 | import { createGlobalStyle } from "styled-components";
2 |
3 | const Colors = createGlobalStyle`
4 | :root {
5 | /* Gueio */
6 | --color-arsenic: #3a4042;
7 | --color-old-silver: #828282;
8 | --color-eggshell: #eae6da;
9 | --color-floral-white: #fffcee;
10 | --color-fiery-rose: #f25a70;
11 |
12 | /* Intermediate */
13 | --color-dark-slate-grey: #385062;
14 | --color-purple-navy: #4c5b84;
15 | --color-pomp-and-power: #7c5e99;
16 | --color-pearly-purple: #b65a97;
17 | --color-pale-violet-red: #d5658c;
18 | --color-tango-pink: #ea767f;
19 | --color-tea-rose: #f78c74;
20 | --color-vivid-tangerine: #f6ad85;
21 | --color-peach: #f5caa1;
22 | --color-bisque: #f7e4c5;
23 |
24 | /* Status */
25 | --color-mantis: #62c370;
26 | --color-tea-green: #c2f9bb;
27 | --color-cardinal: #ba1f33;
28 | --color-rose-gold: #c37472;
29 | --color-sandstorm: #f5d547;
30 | --color-blonde: #f4f1bb;
31 |
32 | /* Links */
33 | --color-lapis-lazuli: #2274a5;
34 | --color-dodger-bue: #20a4f3;
35 |
36 | /* Greyscale */
37 | --color-eerie-black: #191919;
38 | --color-granite-grey: #646165;
39 | --color-pastel-grey: #ced0ce;
40 | --color-platinum: #e6e8e6;
41 | }
42 | `;
43 |
44 | export default Colors;
45 |
--------------------------------------------------------------------------------
/src/styles/settings/Gaps.js:
--------------------------------------------------------------------------------
1 | import { createGlobalStyle } from "styled-components";
2 |
3 | const Gaps = createGlobalStyle`
4 | :root {
5 | --gap-smaller: 5px;
6 | --gap-small: 15px;
7 | --gap-medium: 20px;
8 | --gap-big: 40px;
9 | --gap-bigger: 50px;
10 | }
11 | `;
12 |
13 | export default Gaps;
14 |
--------------------------------------------------------------------------------
/src/styles/settings/Radius.js:
--------------------------------------------------------------------------------
1 | import { createGlobalStyle } from "styled-components";
2 |
3 | export const Radius = createGlobalStyle`
4 | :root {
5 | --radius-big: 14px;
6 | }
7 | `;
8 |
9 | export default Radius;
10 |
--------------------------------------------------------------------------------
/src/styles/tools/Gradients.js:
--------------------------------------------------------------------------------
1 | import { css } from "styled-components";
2 |
3 | export const _gradientBg = css`
4 | background-image: linear-gradient(
5 | 180deg,
6 | var(--color-dark-slate-grey) 0%,
7 | var(--color-purple-navy) 20.83%
8 | );
9 | background-repeat: no-repeat;
10 | background-color: var(--color-purple-navy);
11 | `;
12 |
--------------------------------------------------------------------------------
/src/styles/tools/Separator.js:
--------------------------------------------------------------------------------
1 | import { css } from "styled-components";
2 |
3 | export const _separator = css`
4 | border-bottom: 2px solid var(--color-old-silver);
5 | `;
6 |
--------------------------------------------------------------------------------
/src/styles/tools/Shadow.js:
--------------------------------------------------------------------------------
1 | import { css } from "styled-components";
2 |
3 | export const _shadowBottom = css`
4 | box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.25);
5 | `;
6 |
--------------------------------------------------------------------------------
/src/styles/tools/Typography.js:
--------------------------------------------------------------------------------
1 | import { css } from "styled-components";
2 |
3 | const weight = {
4 | light: 300,
5 | regular: 400,
6 | medium: 500,
7 | semiBold: 600,
8 | bold: 700
9 | };
10 |
11 | export const _h1 = css`
12 | font-weight: ${weight.light};
13 | font-size: 96px;
14 | letter-spacing: -1.5px;
15 | text-transform: none;
16 | `;
17 |
18 | export const _h2 = css`
19 | font-weight: ${weight.light};
20 | font-size: 60px;
21 | letter-spacing: -0.5;
22 | text-transform: none;
23 | `;
24 |
25 | export const _h3 = css`
26 | font-weight: ${weight.regular};
27 | font-size: 48px;
28 | letter-spacing: 0px;
29 | text-transform: none;
30 | `;
31 |
32 | export const _h4 = css`
33 | font-weight: ${weight.regular};
34 | font-size: 34px;
35 | letter-spacing: 0.25px;
36 | text-transform: none;
37 | `;
38 |
39 | export const _h5 = css`
40 | font-weight: ${weight.regular};
41 | font-size: 24px;
42 | letter-spacing: 0;
43 | text-transform: none;
44 | `;
45 |
46 | export const _h6 = css`
47 | font-weight: ${weight.medium};
48 | font-size: 20px;
49 | letter-spacing: 0.15px;
50 | text-transform: none;
51 | `;
52 |
53 | export const _subtitle1 = css`
54 | font-weight: ${weight.regular};
55 | font-size: 16px;
56 | letter-spacing: 0.15px;
57 | text-transform: none;
58 | `;
59 |
60 | export const _subtitle2 = css`
61 | font-weight: ${weight.medium};
62 | font-size: 14px;
63 | letter-spacing: 0.1px;
64 | text-transform: none;
65 | `;
66 |
67 | export const _body1 = css`
68 | font-weight: ${weight.regular};
69 | font-size: 16px;
70 | letter-spacing: 0.5px;
71 | text-transform: none;
72 | `;
73 |
74 | export const _body2 = css`
75 | font-weight: ${weight.regular};
76 | font-size: 14px;
77 | letter-spacing: 0.25px;
78 | text-transform: none;
79 | `;
80 |
81 | export const _button = css`
82 | font-weight: ${weight.medium};
83 | font-size: 14px;
84 | letter-spacing: 1.25px;
85 | text-transform: none;
86 | `;
87 |
88 | export const _caption = css`
89 | font-weight: ${weight.regular};
90 | font-size: 12px;
91 | letter-spacing: 0.4px;
92 | text-transform: none;
93 | `;
94 |
95 | export const _overline = css`
96 | font-weight: ${weight.bold};
97 | font-size: 10px;
98 | letter-spacing: 1.5px;
99 | text-transform: none;
100 | `;
101 |
--------------------------------------------------------------------------------