From 9a8e898be47c85eee683df35f34d49990e1b6169 Mon Sep 17 00:00:00 2001 From: Wellington Braga <64863119+welllucky@users.noreply.github.com> Date: Thu, 4 Jan 2024 02:25:24 -0300 Subject: [PATCH] =?UTF-8?q?Concretiza=C3=A7ao=20do=20Services=20(#4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add new pages and update existing components * feat: :heavy_plus_sign: Adição do Storybook + Story do Input * Add new files and update existing files * feat: :sparkles: Reconstrução da tela de chamado * med * Add ESLint configuration and lint script * Add ESLint configuration and update Prettier settings * Add new components and update existing ones * Update .gitignore and storybook configuration * Add Dockerfile and compose.yaml for containerization * Refactor CustomSelect component * feat: :safety_vest: Concretização do Services * Update Prettier version and add prettier.config.js * Update README.md --- .eslintrc.json | 43 -- .docker/Dockerfile | 36 ++ .docker/compose.yaml | 51 ++ .dockerignore | 34 ++ .eslintrc.js | 110 +++++ .eslintrc.json | 46 -- .gitattributes | 4 + .gitignore | 8 +- .prettierrc | 22 - .storybook/main.ts | 53 +++ .storybook/preview.ts | 57 +++ .yarnrc.yml | 1 + README.md | 2 +- SECURITY.md | 21 - next.config.js | 25 +- package.json | 176 ++++--- playwright-ct.config.ts | 48 -- prettier.config.js | 20 + public/android-chrome-192x192.png | Bin 0 -> 7789 bytes public/android-chrome-512x512.png | Bin 0 -> 21851 bytes public/apple-touch-icon.png | Bin 0 -> 7083 bytes public/favicon-16x16.png | Bin 0 -> 478 bytes public/favicon-32x32.png | Bin 0 -> 974 bytes public/favicon.ico | Bin 0 -> 15406 bytes public/manifest.json | 29 +- .../abrir-chamado/anexar-midia/page.tsx | 7 + .../abrir-chamado/confirmar-chamado/page.tsx | 7 + src/app/(main)/abrir-chamado/page.tsx | 14 + src/app/(main)/abrir-chamado/template.tsx | 69 +++ src/app/(main)/chamados/page.tsx | 14 + src/app/(main)/pesquisa/page.tsx | 11 + src/app/(main)/requests/page.tsx | 5 - src/app/(main)/search/page.tsx | 6 - src/app/(main)/solicitacoes/page.tsx | 10 + src/app/(main)/template.tsx | 14 +- src/app/(main)/tickets/page.tsx | 9 - src/app/layout.tsx | 23 +- src/app/loading.tsx | 4 +- src/app/page.tsx | 37 +- src/components/CalledMobile/index.tsx | 7 +- src/components/CalledMobile/styles.ts | 11 +- src/components/Fieldset/index.tsx | 28 ++ src/components/Fieldset/styles.ts | 35 ++ src/components/FildestInput/index.tsx | 2 +- src/components/FildsetTextArea/index.tsx | 36 -- src/components/FildsetTextArea/styles.ts | 59 --- src/components/Form/FormButtons/index.tsx | 55 +++ src/components/Form/FormButtons/styles.ts | 17 + src/components/Form/index.tsx | 1 + src/components/Headers/Header/index.tsx | 18 +- src/components/Headers/Header/styles.tsx | 42 -- src/components/Input/styles.ts | 75 --- src/components/MediaPreview/index.tsx | 104 ++++ .../{Midia => MediaPreview}/styles.ts | 8 +- src/components/Midia/index.tsx | 104 ---- src/components/NavBar/OptionMenu/index.tsx | 8 +- src/components/NavBar/data/index.tsx | 26 +- src/components/NavBar/index.tsx | 6 +- src/components/NavBar/styles.tsx | 8 +- src/components/PageStruct/style.tsx | 6 +- .../{Searchbar => SearchBar}/index.tsx | 2 +- .../{Searchbar => SearchBar}/styles.ts | 5 +- src/components/SelectOption/index.tsx | 39 -- src/components/SelectOption/styles.ts | 75 --- .../Buttons/AddNewIssueButton/index.tsx | 2 +- .../Buttons/AddNewIssueButton/styles.ts | 2 +- .../{ => common}/Buttons/BackButton/index.tsx | 2 +- .../{ => common}/Buttons/BackButton/styles.ts | 5 +- .../{ => common}/Buttons/Button/index.tsx | 27 +- .../{ => common}/Buttons/Button/styles.ts | 32 +- .../{ => common}/Buttons/IconButton/index.tsx | 0 .../Buttons/IconButton/styles.tsx | 2 +- src/components/{ => common}/Buttons/index.tsx | 0 .../{Icon => common/CustomIcon}/index.tsx | 2 + .../{Icon => common/CustomIcon}/styles.ts | 0 .../{Input => common/CustomInput}/index.tsx | 32 +- src/components/common/CustomInput/styles.ts | 120 +++++ .../{ => common}/CustomLink/index.tsx | 4 +- src/components/common/CustomSelect/index.tsx | 64 +++ src/components/common/CustomSelect/styles.ts | 28 ++ .../common/CustomTextArea/index.tsx | 38 ++ .../common/CustomTextArea/styles.ts | 19 + src/components/common/index.tsx | 6 + src/components/index.tsx | 12 +- src/screens/NoMobileDevice/index.tsx | 11 +- src/screens/NoMobileDevice/styles.tsx | 1 + src/screens/NoMobileDevice/themeTitle.ts | 46 +- src/screens/abrir-chamado/index.tsx | 191 ++------ src/screens/abrir-chamado/styles.ts | 86 +--- src/screens/chamado/index.tsx | 214 +++------ src/screens/chamado/styles.ts | 135 +----- src/screens/home/index.tsx | 5 +- src/screens/index.tsx | 2 + src/screens/login/index.tsx | 14 +- src/screens/login/styles.ts | 16 +- src/screens/meus-chamados/index.tsx | 11 +- src/screens/pesquisa/index.tsx | 4 +- src/screens/solicitacoes/index.tsx | 30 +- src/styles/common/index.tsx | 50 +- src/styles/globals.tsx | 1 + src/types/index.tsx | 6 +- src/utils/functions/buildTestIds/index.ts | 8 + src/utils/functions/index.ts | 1 + src/utils/providers/providers.tsx | 2 +- stories/Form/FormButtons.stories.tsx | 132 ++++++ stories/common/Input.stories.tsx | 227 +++++++++ stories/common/Select.stories.tsx | 67 +++ stories/common/TextArea.stories.tsx | 93 ++++ stories/examples/Button.jsx | 54 +++ stories/examples/Button.stories.js | 45 ++ stories/examples/Configure.mdx | 446 ++++++++++++++++++ stories/examples/Header.jsx | 59 +++ stories/examples/Header.stories.js | 23 + stories/examples/Page.jsx | 68 +++ stories/examples/Page.stories.js | 27 ++ stories/examples/assets/accessibility.png | Bin 0 -> 42336 bytes stories/examples/assets/accessibility.svg | 5 + stories/examples/assets/addon-library.png | Bin 0 -> 467366 bytes stories/examples/assets/assets.png | Bin 0 -> 3899 bytes stories/examples/assets/avif-test-image.avif | Bin 0 -> 829 bytes stories/examples/assets/context.png | Bin 0 -> 6119 bytes stories/examples/assets/discord.svg | 15 + stories/examples/assets/docs.png | Bin 0 -> 27875 bytes stories/examples/assets/figma-plugin.png | Bin 0 -> 44246 bytes stories/examples/assets/github.svg | 3 + stories/examples/assets/share.png | Bin 0 -> 40767 bytes stories/examples/assets/styling.png | Bin 0 -> 7237 bytes stories/examples/assets/testing.png | Bin 0 -> 49313 bytes stories/examples/assets/theming.png | Bin 0 -> 44374 bytes stories/examples/assets/tutorials.svg | 12 + stories/examples/assets/youtube.svg | 4 + stories/examples/button.css | 30 ++ stories/examples/header.css | 32 ++ stories/examples/index.tsx | 4 + stories/examples/page.css | 69 +++ stories/index.tsx | 1 + 136 files changed, 3033 insertions(+), 1407 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 .docker/Dockerfile create mode 100644 .docker/compose.yaml create mode 100644 .dockerignore create mode 100644 .eslintrc.js delete mode 100644 .eslintrc.json create mode 100644 .gitattributes delete mode 100644 .prettierrc create mode 100644 .storybook/main.ts create mode 100644 .storybook/preview.ts create mode 100644 .yarnrc.yml delete mode 100644 SECURITY.md delete mode 100644 playwright-ct.config.ts create mode 100644 prettier.config.js create mode 100644 public/android-chrome-192x192.png create mode 100644 public/android-chrome-512x512.png create mode 100644 public/apple-touch-icon.png create mode 100644 public/favicon-16x16.png create mode 100644 public/favicon-32x32.png create mode 100644 public/favicon.ico create mode 100644 src/app/(main)/abrir-chamado/anexar-midia/page.tsx create mode 100644 src/app/(main)/abrir-chamado/confirmar-chamado/page.tsx create mode 100644 src/app/(main)/abrir-chamado/page.tsx create mode 100644 src/app/(main)/abrir-chamado/template.tsx create mode 100644 src/app/(main)/chamados/page.tsx create mode 100644 src/app/(main)/pesquisa/page.tsx delete mode 100644 src/app/(main)/requests/page.tsx delete mode 100644 src/app/(main)/search/page.tsx create mode 100644 src/app/(main)/solicitacoes/page.tsx delete mode 100644 src/app/(main)/tickets/page.tsx create mode 100644 src/components/Fieldset/index.tsx create mode 100644 src/components/Fieldset/styles.ts delete mode 100644 src/components/FildsetTextArea/index.tsx delete mode 100644 src/components/FildsetTextArea/styles.ts create mode 100644 src/components/Form/FormButtons/index.tsx create mode 100644 src/components/Form/FormButtons/styles.ts create mode 100644 src/components/Form/index.tsx delete mode 100644 src/components/Input/styles.ts create mode 100644 src/components/MediaPreview/index.tsx rename src/components/{Midia => MediaPreview}/styles.ts (82%) delete mode 100644 src/components/Midia/index.tsx rename src/components/{Searchbar => SearchBar}/index.tsx (92%) rename src/components/{Searchbar => SearchBar}/styles.ts (86%) delete mode 100644 src/components/SelectOption/index.tsx delete mode 100644 src/components/SelectOption/styles.ts rename src/components/{ => common}/Buttons/AddNewIssueButton/index.tsx (90%) rename src/components/{ => common}/Buttons/AddNewIssueButton/styles.ts (84%) rename src/components/{ => common}/Buttons/BackButton/index.tsx (91%) rename src/components/{ => common}/Buttons/BackButton/styles.ts (87%) rename src/components/{ => common}/Buttons/Button/index.tsx (60%) rename src/components/{ => common}/Buttons/Button/styles.ts (59%) rename src/components/{ => common}/Buttons/IconButton/index.tsx (100%) rename src/components/{ => common}/Buttons/IconButton/styles.tsx (90%) rename src/components/{ => common}/Buttons/index.tsx (100%) rename src/components/{Icon => common/CustomIcon}/index.tsx (88%) rename src/components/{Icon => common/CustomIcon}/styles.ts (100%) rename src/components/{Input => common/CustomInput}/index.tsx (69%) create mode 100644 src/components/common/CustomInput/styles.ts rename src/components/{ => common}/CustomLink/index.tsx (72%) create mode 100644 src/components/common/CustomSelect/index.tsx create mode 100644 src/components/common/CustomSelect/styles.ts create mode 100644 src/components/common/CustomTextArea/index.tsx create mode 100644 src/components/common/CustomTextArea/styles.ts create mode 100644 src/components/common/index.tsx create mode 100644 src/utils/functions/buildTestIds/index.ts create mode 100644 src/utils/functions/index.ts create mode 100644 stories/Form/FormButtons.stories.tsx create mode 100644 stories/common/Input.stories.tsx create mode 100644 stories/common/Select.stories.tsx create mode 100644 stories/common/TextArea.stories.tsx create mode 100644 stories/examples/Button.jsx create mode 100644 stories/examples/Button.stories.js create mode 100644 stories/examples/Configure.mdx create mode 100644 stories/examples/Header.jsx create mode 100644 stories/examples/Header.stories.js create mode 100644 stories/examples/Page.jsx create mode 100644 stories/examples/Page.stories.js create mode 100644 stories/examples/assets/accessibility.png create mode 100644 stories/examples/assets/accessibility.svg create mode 100644 stories/examples/assets/addon-library.png create mode 100644 stories/examples/assets/assets.png create mode 100644 stories/examples/assets/avif-test-image.avif create mode 100644 stories/examples/assets/context.png create mode 100644 stories/examples/assets/discord.svg create mode 100644 stories/examples/assets/docs.png create mode 100644 stories/examples/assets/figma-plugin.png create mode 100644 stories/examples/assets/github.svg create mode 100644 stories/examples/assets/share.png create mode 100644 stories/examples/assets/styling.png create mode 100644 stories/examples/assets/testing.png create mode 100644 stories/examples/assets/theming.png create mode 100644 stories/examples/assets/tutorials.svg create mode 100644 stories/examples/assets/youtube.svg create mode 100644 stories/examples/button.css create mode 100644 stories/examples/header.css create mode 100644 stories/examples/index.tsx create mode 100644 stories/examples/page.css create mode 100644 stories/index.tsx diff --git a/ .eslintrc.json b/ .eslintrc.json deleted file mode 100644 index 1f83864e..00000000 --- a/ .eslintrc.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "env": { - "browser": true, - "es2021": true - }, - "extends": [ - "next/core-web-vitals", - "eslint:recommended", - "plugin:react/recommended", - "plugin:@typescript-eslint/recommended", - "plugin:react/jsx-runtime", - "plugin:react-hooks/recommended", - "prettier", - "prettier:prettier", - "plugin:prettier/recommended" - ], - "overrides": [], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module", - "project": "./tsconfig.json" - }, - "plugins": [ - "react", - "@typescript-eslint", - "eslint-plugin-prettier", - "eslint-plugin-react" - ], - "rules": { - "indent": ["warn", "tab"], - "quotes": ["error", "double"], - "semi": ["error", "always"], - "no-unused-vars": "error", - "import/prefer-default-export": "off", - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/strict-boolean-expressions": "off", - "@typescript-eslint/consistent-type-imports": "off", - "@typescript-eslint/no-explicit-any": "warn" - }, - "root": true, - "ignorePatterns": ["node_modules/", "build/", "dist/", "public/"] -} diff --git a/.docker/Dockerfile b/.docker/Dockerfile new file mode 100644 index 00000000..5e7fd852 --- /dev/null +++ b/.docker/Dockerfile @@ -0,0 +1,36 @@ +# syntax=docker/dockerfile:1 + +# Comments are provided throughout this file to help you get started. +# If you need more help, visit the Dockerfile reference guide at +# https://docs.docker.com/engine/reference/builder/ + +ARG NODE_VERSION=21.1.0 + +FROM node:${NODE_VERSION}-alpine + +# Use production node environment by default. +ENV NODE_ENV production + + +WORKDIR /usr/src/app + +# Download dependencies as a separate step to take advantage of Docker's caching. +# Leverage a cache mount to /root/.yarn to speed up subsequent builds. +# Leverage a bind mounts to package.json and yarn.lock to avoid having to copy them into +# into this layer. +RUN --mount=type=bind,source=package.json,target=package.json \ + --mount=type=bind,source=yarn.lock,target=yarn.lock \ + --mount=type=cache,target=/root/.yarn \ + yarn install --production --frozen-lockfile + +# Run the application as a non-root user. +USER node + +# Copy the rest of the source files into the image. +COPY . . + +# Expose the port that the application listens on. +EXPOSE 3000 + +# Run the application. +CMD yarn dev diff --git a/.docker/compose.yaml b/.docker/compose.yaml new file mode 100644 index 00000000..7abf8699 --- /dev/null +++ b/.docker/compose.yaml @@ -0,0 +1,51 @@ +# Comments are provided throughout this file to help you get started. +# If you need more help, visit the Docker compose reference guide at +# https://docs.docker.com/compose/compose-file/ + +# Here the instructions define your application as a service called "server". +# This service is built from the Dockerfile in the current directory. +# You can add other services your application may depend on here, such as a +# database or a cache. For examples, see the Awesome Compose repository: +# https://github.com/docker/awesome-compose +services: + server: + build: + context: . + environment: + NODE_ENV: production + ports: + - 3000:3000 + +# The commented out section below is an example of how to define a PostgreSQL +# database that your application can use. `depends_on` tells Docker Compose to +# start the database before your application. The `db-data` volume persists the +# database data between container restarts. The `db-password` secret is used +# to set the database password. You must create `db/password.txt` and add +# a password of your choosing to it before running `docker-compose up`. +# depends_on: +# db: +# condition: service_healthy +# db: +# image: postgres +# restart: always +# user: postgres +# secrets: +# - db-password +# volumes: +# - db-data:/var/lib/postgresql/data +# environment: +# - POSTGRES_DB=example +# - POSTGRES_PASSWORD_FILE=/run/secrets/db-password +# expose: +# - 5432 +# healthcheck: +# test: [ "CMD", "pg_isready" ] +# interval: 10s +# timeout: 5s +# retries: 5 +# volumes: +# db-data: +# secrets: +# db-password: +# file: db/password.txt + diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..3d24738a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,34 @@ +# Include any files or directories that you don't want to be copied to your +# container here (e.g., local build artifacts, temporary files, etc.). +# +# For more help, visit the .dockerignore file reference guide at +# https://docs.docker.com/engine/reference/builder/#dockerignore-file + +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/.next +**/.cache +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/charts +**/docker-compose* +**/compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +**/build +**/dist +LICENSE +README.md diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..196079a7 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,110 @@ +module.exports = { + root: true, + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + }, + globals: { + React: true, + }, + settings: { + next: { + rootDir: ".", + }, + react: { + version: "detect", + }, + "import/resolver": { + node: { + extensions: [".ts", ".tsx"], + }, + }, + }, + plugins: ["@typescript-eslint", "jest", "react"], + extends: [ + "eslint:recommended", + "next/core-web-vitals", + "plugin:@typescript-eslint/recommended", + "airbnb", + "plugin:jsx-a11y/recommended", + "plugin:prettier/recommended", + "plugin:sonarjs/recommended", + "plugin:security/recommended", + "plugin:react/recommended", + "plugin:react/jsx-runtime", + "plugin:react-hooks/recommended", + "plugin:cypress/recommended", + "standard-with-typescript", + "next", + ], + rules: { + "@typescript-eslint/no-unused-vars": "error", + "react/jsx-filename-extension": [ + 1, + { + extensions: [".ts", ".tsx", ".js", ".jsx"], + }, + ], + "react/jsx-props-no-spreading": "off", + "react/prop-types": "off", + "react/require-default-props": "off", + "import/extensions": [ + "error", + "ignorePackages", + { + js: "never", + jsx: "never", + ts: "never", + tsx: "never", + }, + ], + "jsx-a11y/anchor-is-valid": [ + "error", + { + components: ["Link"], + specialLink: ["hrefLeft", "hrefRight"], + aspects: ["invalidHref", "preferButton"], + }, + ], + "jsx-a11y/control-has-associated-label": [ + "error", + { + required: { + some: ["nesting", "id"], + }, + }, + ], + "jsx-a11y/label-has-associated-control": [ + "error", + { + required: { + some: ["nesting", "id"], + }, + }, + ], + "jsx-a11y/label-has-for": [ + "error", + { + required: { + some: ["nesting", "id"], + }, + }, + ], + "no-nested-ternary": "off", + "no-console": "error", + "import/prefer-default-export": "off", + "react/function-component-definition": [ + 2, + { + namedComponents: "arrow-function", + unnamedComponents: "arrow-function", + }, + ], + "react/no-unknown-property": [ + 2, + { + ignore: ["jsx"], + }, + ], + }, +}; diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index b4ad4c23..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "env": { - "browser": true, - "es2021": true - }, - "extends": [ - "standard-with-typescript", - "plugin:react/recommended", - "prettier", - "prettier/prettier", - "eslint:recommended", - "next" - ], - "parser": "@babel/eslint-parser", - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module", - "requireConfigFile": false, - "babelOptions": { - "presets": ["@babel/preset-react"] - } - }, - "plugins": [ - "react", - "eslint-plugin-import", - "eslint-plugin-n", - "eslint-plugin-prettier", - "eslint-plugin-promise", - "eslint-plugin-react", - "eslint-plugin-react-hooks", - "eslint-plugin-tsdoc", - "eslint-plugin-next" - ], - "rules": { - "prettier/prettier": "error", - "react/jsx-filename-extension": [ - "warn", - { "extensions": [".js", ".jsx", ".ts", ".tsx"] } - ], - "import/prefer-default-export": "off", - "jsx-quotes": ["error", "prefer-double"], - "camelcase": "warn", - "complexity": ["warn", 10], - "import/no-unresolved": ["error", { "ignore": ["^@"] }] - } -} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..af3ad128 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +/.yarn/** linguist-vendored +/.yarn/releases/* binary +/.yarn/plugins/**/* binary +/.pnp.* binary linguist-generated diff --git a/.gitignore b/.gitignore index c44f67b4..fe1d2660 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,10 @@ package-lock.json /tests/report/index.html /tests/output/* -settings.json \ No newline at end of file +settings.json + +.horusec/* + +*.log +storybook-static +coverage/* \ No newline at end of file diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index ca9a1678..00000000 --- a/.prettierrc +++ /dev/null @@ -1,22 +0,0 @@ -{ - "tabWidth": 2, - "printWidth": 80, - "endOfLine": "auto", - "arrowParens": "always", - "trailingComma": "es5", - "semi": true, - "useTabs": true, - "singleQuote": false, - "bracketSpacing": true, - "vueIndentScriptAndStyle": false, - "htmlWhitespaceSensitivity": "css", - "insertPragma": false, - "singleAttributePerLine": true, - "bracketSameLine": true, - "jsxBracketSameLine": true, - "jsxSingleQuote": false, - "proseWrap": "preserve", - "quoteProps": "as-needed", - "requirePragma": false, - "editorconfig": true -} diff --git a/.storybook/main.ts b/.storybook/main.ts new file mode 100644 index 00000000..84072610 --- /dev/null +++ b/.storybook/main.ts @@ -0,0 +1,53 @@ +import { StorybookConfig } from "@storybook/nextjs"; + +const config: StorybookConfig = { + stories: [ + "../stories/**/*.mdx", + "../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)", + ], + addons: [ + "@storybook/addon-links", + "@storybook/addon-essentials", + "@storybook/addon-onboarding", + "@storybook/addon-interactions", + "@storybook/addon-themes", + "@storybook/test", + "storybook-addon-mock", + { + name: "@storybook/addon-coverage", + options: { + extension: [".tsx", ".mdx"], + debug: true, + }, + }, + "@storybook/addon-mdx-gfm" + ], + framework: { + name: "@storybook/nextjs", + options: { + builder: { + useSWC: true, + }, + strictMode: true, + fastRefresh: true, + nextConfigPath: "../next.config.js", + }, + }, + docs: { + autodocs: true, + }, + typescript: { + reactDocgen: 'react-docgen', // or false if you don't need docgen at all + }, + build: { + test: { + disabledAddons: [ + "@storybook/addon-docs", + "@storybook/addon-essentials/docs", + ], + }, + }, + +}; + +export default config; diff --git a/.storybook/preview.ts b/.storybook/preview.ts new file mode 100644 index 00000000..0dce3392 --- /dev/null +++ b/.storybook/preview.ts @@ -0,0 +1,57 @@ +import { Preview } from "@storybook/react"; +import { withThemeFromJSXProvider } from "@storybook/addon-themes"; +import { darkTheme, lightTheme } from "../src/styles/theme/default/index.ts"; +import { ThemeProvider } from "styled-components"; +import { GlobalStyle } from "../src/styles/globals.tsx"; +import { + INITIAL_VIEWPORTS, + MINIMAL_VIEWPORTS, +} from "@storybook/addon-viewport"; + +export const decorators = [ + withThemeFromJSXProvider({ + themes: { + light: lightTheme, + dark: darkTheme, + }, + defaultTheme: "light", + Provider: ThemeProvider, + GlobalStyles: GlobalStyle, + }), +]; + +const preview: Preview = { + parameters: { + layout: "centered", + viewport: { + viewports: { + ...INITIAL_VIEWPORTS, + ...MINIMAL_VIEWPORTS, + }, + }, + actions: { argTypesRegex: "^on[A-Z].*" }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + mockAddonConfigs: { + globalMockData: [ + { + // An array of mock objects which will add in every story + url: "http://localhost:0000", + method: "PUT", + status: 200, + response: {}, + }, + ], + ignoreQueryParams: true, // Whether or not to ignore query parameters globally + refreshStoryOnUpdate: true, // This property re-renders the story if there's any data changes + disableUsingOriginal: false, // This property disables the toggle (on/off) option to use the original endpoint + disable: true, // This property disables the panel from all the stories + }, + }, +}; + +export default preview; diff --git a/.yarnrc.yml b/.yarnrc.yml new file mode 100644 index 00000000..3186f3f0 --- /dev/null +++ b/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/README.md b/README.md index 85db56a2..12db3f7f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# FC Services +# Services Desburocratizador de processos de gerenciamento de chamados, bem vindo ao Services. diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 034e8480..00000000 --- a/SECURITY.md +++ /dev/null @@ -1,21 +0,0 @@ -# Security Policy - -## Supported Versions - -Use this section to tell people about which versions of your project are -currently being supported with security updates. - -| Version | Supported | -| ------- | ------------------ | -| 5.1.x | :white_check_mark: | -| 5.0.x | :x: | -| 4.0.x | :white_check_mark: | -| < 4.0 | :x: | - -## Reporting a Vulnerability - -Use this section to tell people how to report a vulnerability. - -Tell them where to go, how often they can expect to get an update on a -reported vulnerability, what to expect if the vulnerability is accepted or -declined, etc. diff --git a/next.config.js b/next.config.js index 21f11ca4..10efd272 100644 --- a/next.config.js +++ b/next.config.js @@ -1,6 +1,13 @@ /** @type {import('next').NextConfig} */ const nextConfig = { basePath: "", + generateBuildId: async () => { + return `build-id-${new Date()}`; + }, + compiler: { + styledComponents: true, + removeConsole: true, + }, pageExtensions: ["mdx", "md", "jsx", "js", "tsx", "ts"], experimental: { webVitalsAttribution: ["CLS", "LCP", "FCP", "FID", "TTFB", "INP"], @@ -11,15 +18,15 @@ const nextConfig = { }, }, optimizeFonts: true, - redirects: async () => { - return [ - { - source: "/", - destination: "/tickets", - permanent: false, - }, - ]; - }, + // redirects: async () => { + // return [ + // { + // source: "/", + // destination: "/chamados", + // permanent: false, + // }, + // ]; + // }, }; module.exports = nextConfig; diff --git a/package.json b/package.json index 4b379a14..3c439f68 100644 --- a/package.json +++ b/package.json @@ -1,72 +1,108 @@ { - "name": "services", - "version": "0.1.0", - "private": true, - "repository": "https://github.com/welllucky/services.git", - "author": "Wellington Braga ", - "license": "LGPL-3.0-only", - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", - "lint": "next lint && yarn lint:css", - "lint:css": "stylelint './src/**/*.js'", - "e2e:open": "playwright test --ui", - "e2e:run": "playwright test", - "e2e:debug": "playwright test --debug", - "e2e:gen": "playwright codegen", - "test": "playwright test -c playwright-ct.config.ts" - }, - "dependencies": { - "@vercel/analytics": "^1.1.1", - "axios": "^1.4.0", - "next": "14.0.1", - "react": "^18", - "react-dom": "^18", - "sharp": "^0.32.6", - "styled-components": "^6.1.0", - "swr": "^2.2.4", - "usehooks-ts": "^2.9.1" - }, - "devDependencies": { - "@babel/eslint-parser": "^7.23.3", - "@babel/preset-react": "^7.23.3", - "@next/eslint-plugin-next": "^14.0.3", - "@playwright/experimental-ct-react": "^1.39.0", - "@playwright/test": "^1.39.0", - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "@typescript-eslint/eslint-plugin": "^6.4.0", - "@typescript-eslint/parser": "^6.11.0", - "dotenv": "^16.3.1", - "eslint": "^8.0.1", - "eslint-config-next": "14.0.1", - "eslint-config-prettier": "^9.0.0", - "eslint-config-standard-with-typescript": "^39.1.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", - "eslint-plugin-prettier": "^5.0.1", - "eslint-plugin-promise": "^6.0.0", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-tsdoc": "^0.2.17", - "postcss-styled-syntax": "^0.5.0", - "prettier": "^3.1.0", - "stylelint": "^15.11.0", - "stylelint-config-standard": "^34.0.0", - "typescript": "*" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } + "name": "services", + "version": "0.1.0", + "private": true, + "repository": { + "type": "git", + "url": "git+https://github.com/welllucky/services.git" + }, + "author": { + "name": "Wellington Braga", + "email": "wellingtonbat.wl@gmail.com" + }, + "license": "LGPL-3.0-only", + "scripts": { + "dev": "next dev", + "build": "next build", + "lint": "next lint", + "e2e:open": "playwright test --ui", + "e2e:run": "playwright test", + "e2e:debug": "playwright test --debug", + "e2e:gen": "playwright codegen", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build", + "chromatic": "npx chromatic --project-token=chpt_79aa966e7eb4a6e --auto-accept-changes", + "test-storybook": "test-storybook" + }, + "dependencies": { + "@vercel/analytics": "^1.1.1", + "@vercel/speed-insights": "^1.0.2", + "axios": "^1.4.0", + "next": "14.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-hook-form": "^7.49.2", + "sharp": "^0.32.6", + "styled-components": "^6.1.0", + "swr": "^2.2.4", + "usehooks-ts": "^2.9.1" + }, + "devDependencies": { + "@babel/eslint-parser": "^7.23.3", + "@babel/preset-react": "^7.23.3", + "@next/eslint-plugin-next": "^14.0.3", + "@playwright/test": "^1.39.0", + "@storybook/addon-coverage": "^1.0.0", + "@storybook/addon-essentials": "^7.6.7", + "@storybook/addon-interactions": "^7.6.7", + "@storybook/addon-links": "^7.6.7", + "@storybook/addon-mdx-gfm": "^7.6.7", + "@storybook/addon-onboarding": "^1.0.10", + "@storybook/addon-themes": "^7.6.7", + "@storybook/blocks": "^7.6.7", + "@storybook/nextjs": "^7.6.7", + "@storybook/react": "^7.6.7", + "@storybook/test": "^8.0.0-alpha.7", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "@typescript-eslint/eslint-plugin": "^6.4.0", + "@typescript-eslint/parser": "^6.11.0", + "chromatic": "^10.2.0", + "dotenv": "^16.3.1", + "eslint": "^8.0.1", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-next": "14.0.1", + "eslint-config-prettier": "^9.0.0", + "eslint-config-standard-with-typescript": "^43.0.0", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-jest": "^27.0.1", + "eslint-plugin-jsx-a11y": "^6.6.1", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-promise": "^6.0.0", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-security": "^1.5.0", + "eslint-plugin-simple-import-sort": "^7.0.0", + "eslint-plugin-sonarjs": "^0.15.0", + "eslint-plugin-storybook": "^0.6.15", + "eslint-plugin-tsdoc": "^0.2.17", + "postcss-styled-syntax": "^0.5.0", + "prettier": "^3.1.1", + "storybook": "^7.6.7", + "storybook-addon-mock": "^4.3.0", + "typescript": "*" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "resolutions": { + "jackspeak": "2.1.1" + }, + "bugs": { + "url": "https://github.com/welllucky/services/issues" + }, + "readme": "ERROR: No README data found!", + "homepage": "https://github.com/welllucky/services#readme", + "_id": "services@0.1.0" } diff --git a/playwright-ct.config.ts b/playwright-ct.config.ts deleted file mode 100644 index 3f194bd7..00000000 --- a/playwright-ct.config.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { defineConfig, devices } from "@playwright/experimental-ct-react"; - -/** - * See https://playwright.dev/docs/test-configuration. - */ - -require("dotenv").config(); - -export default defineConfig({ - testDir: "./tests/", - testMatch: "**/?(*.)+(spec).[tj]s?(x)", - /* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */ - snapshotDir: "./tests/__snapshots__", - /* Maximum time one test can run for. */ - timeout: 10 * 1000, - /* Run tests in files in parallel */ - fullyParallel: true, - /* Fail the build on CI if you accidentally left test.only in the source code. */ - forbidOnly: !!process.env.CI, - /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, - /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, - /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: [ - ["html", { outputFolder: "./tests/report", host: "localhost", port: 4000 }], - ], - /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ - use: { - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: "on-first-retry", - - /* Port to use for Playwright component endpoint. */ - ctPort: 3100, - }, - - /* Configure projects for major browsers */ - projects: [ - { - name: "chromium", - use: { ...devices["Desktop Chrome"] }, - }, - { - name: "firefox", - use: { ...devices["Desktop Firefox"] }, - }, - ], -}); diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 00000000..922804a7 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,20 @@ +module.exports = { + "bracketSameLine": true, + "htmlWhitespaceSensitivity": "css", + "arrowParens": "always", + "bracketSpacing": true, + "embeddedLanguageFormatting": "auto", + "endOfLine": "lf", + "insertPragma": false, + "jsxSingleQuote": false, + "printWidth": 80, + "proseWrap": "preserve", + "quoteProps": "as-needed", + "requirePragma": false, + "semi": true, + "singleQuote": false, + "tabWidth": 2, + "trailingComma": "none", + "useTabs": false, + "vueIndentScriptAndStyle": false +} diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..3c87804b0ef58709992ae4190df59dd49a19bd2d GIT binary patch literal 7789 zcmZ{pWmr_t+sAj81(uRn1SFS68kAO8x|aqCDQW3OK$b?j1f;vWLrOxBkZx&^PU-sZ z?|NQ8FV30!I%j6CnYqrK`P|>{7gdBT9yU2P006*~my=RQm0kZ`5De5^eaRLRRRCSo zWhDTWqm;V<05!9`l(?p+;o*BspXXYakJ|-TK?Fp4tc-~aa>p!vAxJ#QfM!nC@Gd=; z+)8pCTQ-(5t+6xz|&jO+9a{q@87(+DiY1(+N zMq5@|jJA_B!0+hjf(9uh-YQ#Y=)dOw7n1RZEX|C7v`&YyqWF_CP>Qfp4R2Z8(AHh9rpMFz6H@BiUqFg`t@hxV~;I{DOJ`-NK0nY!YBl;prU>FQbQrryWoRxBOA(eTAyf zF>zO=fE+yS7Dxk6Dgtgn+zqW~_ra9F8^~C`3W@S|XH|@7dqE#KzoZAM=mxXEMZ+TbyS5o2~W_OJ~OUI-0Zx7jPpuCkc})1Q{sVTE%SPHkv4_j`6qwF zV#IzC185VDIqp+L(9U!~1y8Rq`}>_M8p%&Ukc2h?;5d$?&qfDJ@#r*LDq9r*nr+05D(Pk6@?fd#@Fe&q?}CqUWW2++uM>F6A1Md6 za=OnKcHP!<1Sd)&p>QE~FBNhrR1he$!O9j2U`9H>JIj0>h6*sE`n9y50TF<$>dm*- z1gHRyJgTgm5|j@3WiseJ0Ye4ae5n9ZOaV`kyY4^ZIQG%Yjvi+r5$zO80aOP{m(|dN zxwrYcwq{~cru5{)ZpEc+vRb|`Soeq2)bs=5_drv8Gw-zY>D@=Mva6>Ty}|TL4zPgl zJ>&Cj6h7$>YgWg&-U&ThG_w4==-pudM@Vu{t#sVI3)chTh}CO>>}~_Un`2>30ZqE9 z``5J!2w24qw>lR?USo}($zjwi6*E#QZ4&J6<`~+RC-7rIijLP9{0S3RT7P!tlr6tX z+-A*$^7mrY2d_3Y^^BPCR`tt^)d^>?AW$#*x%b5Q=!+aXy0IPyzz?6ixy>u58oOsa zbUokV6Xdvr!>4l1?$xXD3;2RbqK8vrTtM|>NA(soW4khucoE{+9v+^8H`Q+6Q-hLJ z_%6P(lnTe>*R8A-{qsZwS>X0!IpQI$qK?*T>mUM{VgDm`bYr~2&PZ@h$j13-Ooz7f4F%??U0>xZ zqqT!Rqj{OMAx6{;D!HMpw}zo}qBwK6nKSpF2#de6EYOb2rqnenUlrY((j4Sf*;a2@rtJf3gP`^&zaR9>$+tFvxA8Z&$d ztGdTM-(n`UaJEZg+vHU?0$O@|xa*8pZII#Oq(YqA8$(o;B-X!GogOWtw?1K$1pw+t zk5`=7sj08Yag@{)th^-sS-;G$z-WE(u**i-rrqiu2y*UR$%6IUlx3?`R7k8OpOocw zT@LVkywA``^7C|fz(Ak(iyNmVLu1oTF{bXr9oKB`nag1he;cbAV=96!asMn{_QZB! zk&RiW=YpA&_dMb=;R=t``gp(hj`_gAqy0Nd`y*lHI10msF?;1F+?Arr-o8B$Nq;eh zHJyagrcY4)Zbg_v{TH#+HngFu5lJt*FLb`870^G>?4~ExH{K5l(g?LP)=}e;aRJBG zC6ZW|Z{%AOGJdo&!As~mnE3Oo6Vw(r%U*N7+aKqBOKQ;GLy-uL?HEt|wa;i~CMpT5 zCpTHAUcVLx*hM+Zs%ESXjGcQ|N1Nz`&*baf5{z!6(zi38oOoIHI2%K5D{h~?hZUI%Zo7@y6*4mOkESz3ct0xb(AEkP%q@zuvP)}NqNc7P2rJVVk zV~+*T@)N#zF?D01OP0wli1di3mUMFKDF19bEjU&tA_CZ1eL*)g9>c5N%hSqNYuK%XN^;Q)Jg^(`Jqj8I8PiBa3>0W@tkCQ9an8P)zvxjeEwU zx(#WmZIM1G*5N5}z$;$7NF#=^ji$Q<2b1wCCn;p}%vWR9y7{=Zb4XRbcXZNdZ6lCt z=a-vaGB~?eL$Tk%{0L1wD4Jg&>lU)Fu`J=6Cwg`;mbrQ}US>`ON#_!aN^V*S{ZUH! zvbwZ3iW3W-)~REEufV&C{?+pI_SspuQu0zLIfeVxeoRY`wwxih+BJh$1ohBjLI0Zk zgnTl%xo*~W33?jD052YI>iiruEo-RJ8zWmwq;0ihdmIvq!EX9lN_{JI>g)CE8yfYr zvdWAj2z)uQ{^oE^K$U1NQSYS2!C`DFu80whibyciF6=$!5{LC=r{${%jg#RS`S^v> znz;X(#5;YM>0WuOO0*p6(p2~RyJ7H&m&rf9ZBq_umdds6s0Y`C58OKeEX^g>mLa}chYGcOsvMhFVC|Yygm&{B^Bu5=Zb*-?F*8`Jo|)3d}3b`>wP|{ z&%9<}om!yGcX3~xjg|7sti&uM`5<$UcVt)GRTep(Gv3^}avq;sI52NFere4fp!l0; zl`yhk1ImDZ`hfP^SifI*@Njxc)dSqzvS{S!kX6Je?W^|bw6Be(zi$u6rZ#T9bu6PR z)PpjpEU1d%rKCTv(bJhj-$ku-Xe)hJ&`IdKR_M!;p_f&U6TLz#WgNA^9C{ZS%cFLT zZDEr#&9#-~S{Ds7L$0!b@S6e=WZ{Hl62RjP7oh|5+rq_Fe8p<+Uv;RCGTJRncnRSW zJ_o4p4A;Ax7*EFObV5rBcx_Mso%LxbAPB~|k+rA#JxFqZ%Z>l=UO`J2!TNRKsyp*EJv*jaAvb@+7YZPm3ETLbTYmc>R{5PmXO{FGCRe|^iJ?W~}AlC<# zOD64&hzL;vRP%v1iO+Apm<+)g)xHua#Jj;P**+`j}qF;|vv@_%Rz;>=Z7*`y?3;c?gy8I*^iQ56K7pQL3ocd~N zba^%BedMiegtSlkNMQpXbvKv_M4CY0u_B9YrV3MUBC#?+!c2B}*4(ojK3*ie;nDus z_NwSNbp@RPkRN@Q5VCLpSl}z7we4!f@x!cjyffw?&kM%oigGqfBeY-QiRo>4KhHh# zN~2fU2D-Hn`aOimu3W~keCilupR3(?`k$M~$Gb+isD=Z?nkoW>Fr14yTQE&>3FTaF zen$h8Bw8gZ2Vr=0pnF_o1|kgKGZv_+Exf6>7S&1W=bxz8%%A7FwQZJ}USjh6n z0;qEMKg%>Jch@%Sax5X!E1){08rTZx!1&hp(~-rJLd2q?d{$P5zYNKgqag{+#^O@Q zlhZQqcgw(5DdI1^CN~&N+6)&T$`2G03z!g0njx-zkjxw4T4fl1P~1oE@a5ba9G!J! z7p=hDjmD}rQnZCwzuLUE(b3fjAC4z({D$BX4ygY@A2MLgido0jum!$`vTEwUSdAIj zY8FP@>n1$emT9(lODnl#cD#9RN$eM6D6$D|4mWSlSX^s7!G!ZQe9w5$ ze3G^z#}L}58dB_4d2u?xA{;)kKzEetgm>u-dVO9Ng$N6ArH*;b=;sL)ekt!^ce=Kr81(u$pmG)>=SJ8_vIopZ5(Dm)`8vW=`UstEm*vC`B}vG(xvk{f|v94Fajn3ytfZ@5Zx#mU(gok$8&!Fi)CW z@iA0;Vs)V^2hT}-OE>8$Y>6Y1E*-#M|5~dS_u`AORG5tz$n{1>V4Qfsf$e1#N4IQf z=1>1ReYi>HCsG99>$?=Xshx?#3H1`vMb*itB9_J(lG3k@mpi7CQ*x_dtHb%}fGffm zRwbMJ3)E_dvb70}!p@9WhciUZeUGbMb#lL!m-MRY2fYP>wxBk1u7WQ#J5v%C zcWNijXXZH>Gs|+5&Q>?eErO{{8ckpPg@Ej75&V7&J>wMb7cb4NX}lXKB4JsMb7_fdb?3MSn;i?-lMx_P8C_u=vj$%IOtD2F0ifj9ppN zg=3>4pG3nUPbMeMms&nv|4zF}Qz9Cc??VNFt`Y$9kc>f~i5=ZL+@9FcrXPz18K!w` z<-^_jU+Uu2e3WWLr^g7Hk>uss)z3C-$oDAxOX5^=(u~BUKQTA$*?rru**l?oU*NL| zRyF%nTnELz>?}he#?+x`v&g3!O>XC)+WGd|b0bt=nh1eXn<1=hRu`5k+&)&-*r&Jc zS#a4Z&RV1DrvrS?S58R>pQk2(%t$?U6Y00_9_eGahiPs^U3wGfHwBwcLa|!Euy254 zUs1fCX-u#reIsi7;*MzGi`{a3BX$<$Z73)2dl!(EEzyu#a{6)QM?W;`7ypFYBx6}O zd8v}Q(Oosl-PXWkt>_$6S)5}`A;00Sn+7=gkC%eea^Bv*KgbQP(6`_>yhcqWf>BQm z-#Nqcuuyr2!AV2u4tY&qwb3@EqNnz8|9d#JOSrkTW41fPp$~;B@`&pT-#vwL(KFUC zTs;y5fJ0v;mt9Qj24__w8vo;rC`I#uU0c|@a%q={A~E{E+(BDCw0zxo>n zeZX-S+QSp=%Y*o6c-Gx1=ce@=C?7L&q%iByNNL=>F7*508Hp~d=IHKj1vE}S$=X^& z>+SFV7Qeod7nK+MOz27O8EUEM<0@=MqKhqsyA&)S8i%lqYj!UtVfo4q>}01vABKLs zH*FX0W>#-1=$Mh8x9j@ocaLUiRGuYVq7%@Xc3*AijyrHfY-7Ra39VlJT{F88ZX9%M zL-+;Xhud;2s>L5^V%uECHZhpUmduda=e&i7LG zA$Q47`mksp5V4R&iE89Y#Gg;+io6L~@);+tN-#q5e32 zch`=h!z(%UEF0|aH6Jk)N^uw(bQI}FpvWcf4|$nCu8$@eKPXrOEPaFsG++N)RzAHbbE;p3x1tPc>aBm@o)MV7K3TIoB8@*U2;vmUoR?K<8c`i<6+(8 zly~F{$9v~@pzPyv<~w2;F^LXbXm#(!`LMqB7lqg2C2A(-oQ8`+@6QF&IDkl^Lr(H0 z!f1B{hu8hnTS?9_w#$*9Iq6_|6xhm;mG(%j*6#Q8b6$s%v*>B6=_KJ z)P5Z%S9kVklU#o|;xma|C;kn&M-V;0Rq{V{PT@IuJ}6TVqN$tVv*ebBrOREThlYP? z)XO?9_xyI`Y5V9~YcVX30u(Dbd-kQxtN^>{pPyKM#gAW`$@!yrT1|NgSzbLWk|_@P z>~E8qM!T2mRtEPZIilPo0U+1QRRNwip7HFqC9$uc2hSxuR8%HOBp)dnntXBDf|v)T zJd8kM*@CF0bih0F_S~7|H?-*o@6F~5n_2Nud1w#UjW?g)FL8Kmryojxh{Q^x!y&c# ze%j01s523<6Anl`*sU=+uKxAXIp__Qi^8jus<$qVjjy#3I{Xg%rpF;DK1H2`c)y^m zvf*WCr)R$>WAmIan^!($vw>98_vbikQr!Q%3Qr{GKL|DZEpG+?WiXEmx%D^q5 zQn&a&^D|$G3v?(zDjrtkKT-ZXC;GaB;Pc&y1_ZGS^}pr+XB6&l@ZPAKzppH&Bf7Me zx9_$=Ms{=4UA9V>3@VIHJt|rozxrs{85G%Yy{VeM4K;aq;esM+450`_PykZ^(GOO} z&AZ3>I335cA3)90NC+{R)K~fsc_h`KMFjp{(D?=lb(-OX|i=21xOd{Y47KzsVPWW6leT>p* zQp_$CpTygtM>DcakQsdFnuZswk_$8c<`V0vEsWcEr>o5KYhU4=IM#w{!p5J1tWRN@ z%bL}p?O#4quI}ximtq_rZQ{|8`dzoUNr^NeASV!$kKV$w4tPS|JkL=(Oj3LB%Zz8n z$a0Q1h@dtR%d5Xjhwvr6{k!nsfr>i(xutKW@_r8ofp} zWO(2p@X|dR_FGwaI!E5* z2(k01oOD6;3I828b=9QMt1Gdtn)SK3lsIgK}s4!IIYp17!p3LeVmHjc?w6txw3oI`M|df>nOxQ@~fdV)~`fE4b5E4{F{+vGIUw^}0& zN{5MWBLkdo%~S4WM+k$Ut16IrEcX-lQ`wbg0@ZZRb_QsvJ*v}B2*WZl^YZTK;orKA zI2E%OTI99}B1o|tx-&QC?Gnqut7d5AKvRgaSgAJ3WNpk873HaD4 z0(pE~%Z-!R+y}A7^yG}z-YQeeG@STI7pnIXP&p#{i)IzFg9{`q zCd%EAbcR8wT>1G$DWl=%kT6qD4u5wL+4%kBJytaGhyZ1;RN;A3 zVc+Scs-9&sq$(L<`_L~@8r-kA1tB3}0rNhg1nrG3WKyA20O36=A0HM<|80T+e`9h+ zB}1A$bDQ3ufFs*V^e2yKq&)$_N$`9SCOC|p)s_j&4qPoy1D^Rif-6xj5*XzoW!!MK z0V3X05t;F0rAZ_IKKnZ_)ub|`?r$ysU3 z&)C3q2TlUpm&9j$V3RimBU1t(A6E=%q{6waA!!2N7bY>26HJ=yx!;m){4?~_NZzeJ zyl`HcMjJvw2vB2Ic~Hr2;shTY77@6cOx?W!uGvdpgjpV7+Wf=j=$H;_tA2sau37zck5V9z>6x- z&d?QjkC$b(un#ikaBEh_B3ehwzyFi1p_LVAC6u@z^18eRVE__O8C%ym!xRG9h{K5m zx*3M|omgKzTn%Nel+F6UhPUX|#d{41Asfl&HZ`2H8?2Bi)c=abSbkFNZ$qq2CSXc0 zh=78IXiiQxAJh*ZV*pV#qfuoA*}#!PjldRyYSJ$LHkto3J}1?Rd_b=+U=k_cX{RR5 zDjnET59z?&_P8(^apE2+@e>jNDYaoq$jh9MR4j334X|)hTF48eqb4y0v{$B$Snvxe jKgx9dIN0kTvGW9IxK)JJ$}1sI{xLva8X;9FVI1&3Yp|>U literal 0 HcmV?d00001 diff --git a/public/android-chrome-512x512.png b/public/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..6f00ff14b3b63c31e03725668492a3562789f126 GIT binary patch literal 21851 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 literal 0 HcmV?d00001 diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8d04c39fa098a811d88a3e07f269c4269d0c7b24 GIT binary patch literal 7083 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 Hn+5+Ltu>C2 literal 0 HcmV?d00001 diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..0237f814b4daaaaa2f9e1580ee151ba8cf348b5f GIT binary patch literal 478 zcmV<40U`d0P)Px$m`OxIR5(wilSwFqVH}5_&ulTa6d_|POOzT*5|e3eq=*9%C*UeB2vP$PzWjx9b4EBW_fsV`DFAFXq5h#jT1y@V^}-0 z;`Y3f5otgnDCxFVapgMolK2QpQX42ruA_aS1efTPV5OfLi)o6>`$I-nTIB_eIRgY~ z!WgnQd4UmH9a?n=`!}2Ng2IFf>a%+pU2S9KXdVwf70C+(1j^H!DNSp_CEl`evCR6J zjkVK7Ufj<=m-tD%$JIv}(MKD}j5gtTyk>Bzp7XnX`2^p+r2thBE&0PznLXBOc|l%m zF(=MFj-5MRpdr4DI(;V%GuiTjj>2&?$^iOpwLH7Uk2R`jGmJ?IdTllGf|%eWx=fRZ zua9h8*d;h4vOtpd*=jj*Z2#OrpgM$txKebXDH43_+{Jz{$GzzIb_@UfO#l4OZ)A0w U?Iic}ng9R*07*qoM6N<$f~P&zg8%>k literal 0 HcmV?d00001 diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..65c8ed5016235001bee236686ad92abeca2702d2 GIT binary patch literal 974 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 +

AttachMediaPage

+ + ); +} diff --git a/src/app/(main)/abrir-chamado/confirmar-chamado/page.tsx b/src/app/(main)/abrir-chamado/confirmar-chamado/page.tsx new file mode 100644 index 00000000..90d9ec3b --- /dev/null +++ b/src/app/(main)/abrir-chamado/confirmar-chamado/page.tsx @@ -0,0 +1,7 @@ +export default function ConfirmDetailsPage() { + return ( +
+

ConfirmDetailsPage

+
+ ); +} diff --git a/src/app/(main)/abrir-chamado/page.tsx b/src/app/(main)/abrir-chamado/page.tsx new file mode 100644 index 00000000..34b6c918 --- /dev/null +++ b/src/app/(main)/abrir-chamado/page.tsx @@ -0,0 +1,14 @@ +import { CreateTicketPage } from "@/screens"; +import { Metadata } from "next"; + +export const metadata: Metadata = { + title: { default: `Abrir chamado`, template: "%s | Services" }, +}; + +export default function Issue() { + return ( + <> + + + ); +} diff --git a/src/app/(main)/abrir-chamado/template.tsx b/src/app/(main)/abrir-chamado/template.tsx new file mode 100644 index 00000000..b126bb21 --- /dev/null +++ b/src/app/(main)/abrir-chamado/template.tsx @@ -0,0 +1,69 @@ +"use client"; + +import { BackButton } from "@/components"; +import { IssuePageContainer } from "@/screens/chamado/styles"; +import { Column, Row, TitleComponent } from "@/styles"; +import { FormButtons } from "@/components/Form"; +import { ReactNode, useMemo } from "react"; +import { usePathname } from "next/navigation"; + +interface PageRouterData { + page: string; + title: string; + hasBackButton?: boolean; +} + +export default function Template({ children }: { children: ReactNode }) { + const pathName = usePathname(); + const pagesTitles: PageRouterData[] = [ + { + page: "/abrir-chamado", + title: "O que aconteceu?", + hasBackButton: false, + }, + { + page: "/abrir-chamado/anexar-midia", + title: "Anexar mídia", + hasBackButton: true, + }, + { + page: "/abrir-chamado/confirmar-chamado", + title: "Confirmar informações", + hasBackButton: true, + }, + ]; + + const actualPage = useMemo( + () => pagesTitles.find((page) => page.page === pathName), + [pathName, pagesTitles] + ); + + const indexPageFinder = useMemo(() => { + return pagesTitles.indexOf(actualPage as PageRouterData); + }, [actualPage, pagesTitles]); + + const nextPageUrl = useMemo(() => { + return indexPageFinder === -1 + ? "/" + : indexPageFinder + 1 >= pagesTitles.length + ? "/" + : pagesTitles[indexPageFinder + 1].page; + }, [pagesTitles]); + + return ( + + + + + + {actualPage?.title} + {children} + + + + ); +} diff --git a/src/app/(main)/chamados/page.tsx b/src/app/(main)/chamados/page.tsx new file mode 100644 index 00000000..7ac6b0d3 --- /dev/null +++ b/src/app/(main)/chamados/page.tsx @@ -0,0 +1,14 @@ +import { MyCallsPage } from "@/screens/meus-chamados"; +import { Metadata } from "next"; + +export const metadata: Metadata = { + title: { default: "Meus chamados", template: "%s | Services" }, +}; + +export default function Tickets() { + return ( + <> + + + ); +} diff --git a/src/app/(main)/pesquisa/page.tsx b/src/app/(main)/pesquisa/page.tsx new file mode 100644 index 00000000..bc40fdd3 --- /dev/null +++ b/src/app/(main)/pesquisa/page.tsx @@ -0,0 +1,11 @@ +import { issueMobileData } from "@/screens/home/data"; +import { SearchPage } from "@/screens/pesquisa"; +import { Metadata } from "next"; + +export const metadata: Metadata = { + title: { default: "Pesquisa", template: "%s | Services" }, +}; + +export default function Search() { + return ; +} diff --git a/src/app/(main)/requests/page.tsx b/src/app/(main)/requests/page.tsx deleted file mode 100644 index 3af99946..00000000 --- a/src/app/(main)/requests/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import RequestsPage from "@/screens/solicitacoes"; - -export default function Requests() { - return ; -} diff --git a/src/app/(main)/search/page.tsx b/src/app/(main)/search/page.tsx deleted file mode 100644 index 19efe668..00000000 --- a/src/app/(main)/search/page.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { issueMobileData } from "@/screens/home/data"; -import SearchPage from "@/screens/pesquisa"; - -export default function Search() { - return ; -} diff --git a/src/app/(main)/solicitacoes/page.tsx b/src/app/(main)/solicitacoes/page.tsx new file mode 100644 index 00000000..355b3a5f --- /dev/null +++ b/src/app/(main)/solicitacoes/page.tsx @@ -0,0 +1,10 @@ +import { RequestsPage } from "@/screens/solicitacoes"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: { default: "Chamados solicitados", template: "%s | Services" }, +}; + +export default function Requests() { + return ; +} diff --git a/src/app/(main)/template.tsx b/src/app/(main)/template.tsx index 3464a651..bba9536f 100644 --- a/src/app/(main)/template.tsx +++ b/src/app/(main)/template.tsx @@ -6,7 +6,7 @@ import { FlexContainer } from "@/components/PageStruct/style"; import { NoMobileDevice } from "@/screens/NoMobileDevice"; import { useApp } from "@/utils"; import { usePathname } from "next/navigation"; -import { ReactNode, useDebugValue, useEffect, useMemo, useState } from "react"; +import { ReactNode, useEffect, useState } from "react"; import { useIsClient } from "usehooks-ts"; export default function Template({ children }: { children: ReactNode }) { @@ -19,11 +19,7 @@ export default function Template({ children }: { children: ReactNode }) { }, [isClientMediumMobile, isClientMobile, isClientSmallMobile]); const isClient = useIsClient(); - useDebugValue(isMobile); - - const isRequestsPage = useMemo(() => { - return usePathname() === "/requests"; - }, [usePathname]); + const isRequestsPage = usePathname() === "/solicitacoes"; if (!isMobile && isClient) { return ; @@ -31,12 +27,12 @@ export default function Template({ children }: { children: ReactNode }) { return ( + $backgroundColor={isRequestsPage ? "#E2F3D5" : "#F5F5F5"} + $full={true}> {children}{" "} diff --git a/src/app/(main)/tickets/page.tsx b/src/app/(main)/tickets/page.tsx deleted file mode 100644 index ad6c6a7a..00000000 --- a/src/app/(main)/tickets/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import Homepage from "@/screens/home"; - -export default function Tickets() { - return ( - <> - - - ); -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 2c0c6485..64762759 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -2,17 +2,16 @@ import type { Metadata } from "next"; import { Inter } from "next/font/google"; import StyledComponentsRegistry from "@/utils/providers/registry"; import { AppProviders } from "../utils/providers/providers"; -import { Suspense } from "react"; -import Loading from "./loading"; import { Analytics } from "@vercel/analytics/react"; +import { SpeedInsights } from "@vercel/speed-insights/next"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { - title: "FC Services", - description: "Generated by create next app", - applicationName: "FC Services", - creator: "SQUAD 1 by Senac PE X Porto Digital", + title: "Services", + description: "Desburocratizador de processos de gerenciamento de chamados, bem vindo ao Services.", + applicationName: "Services", + creator: "SQUAD1 X L3", authors: [ { name: "Wellington Braga" }, { name: "Larissa Ferreira" }, @@ -21,8 +20,7 @@ export const metadata: Metadata = { { name: "Cleyton Cabral" }, ], category: "Helpdesk", - icons: - "https://fercos-s3-ecommerce.s3.amazonaws.com/favicon/apple-touch-icon.png", + icons:["/favicon.ico","/favicon-16x16.png","/favicon-32x32.png","/android-chrome-192x192.png","/android-chrome-512x512.png"], manifest: "/manifest.json", }; @@ -34,12 +32,11 @@ export default function RootLayout({ return ( - - - }>{children} + + + {children} - - + ); diff --git a/src/app/loading.tsx b/src/app/loading.tsx index b23ec452..539c20ac 100644 --- a/src/app/loading.tsx +++ b/src/app/loading.tsx @@ -1,12 +1,12 @@ -import { FcLogoMobile } from "@/assets"; import { LoginMobile, Logo } from "@/screens/login/styles"; +import Image from "next/image"; export default function Loading() { // You can add any UI inside Loading, including a Skeleton. return ( - + Services logo ); diff --git a/src/app/page.tsx b/src/app/page.tsx index 6f43cfc5..3e3c9114 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,5 +1,38 @@ -// import Homepage from "@/screens/home"; +"use client"; + +import { NavigationBar } from "@/components"; +import navigationOptions from "@/components/NavBar/data"; +import { FlexContainer } from "@/components/PageStruct/style"; +import { NoMobileDevice } from "@/screens/NoMobileDevice"; +import { Homepage } from "@/screens/home"; +import { useApp } from "@/utils"; +import { useEffect, useState } from "react"; export default function Home() { - return <>{/* */}; + const { isClientMediumMobile, isClientMobile, isClientSmallMobile } = + useApp(); + const [isMobile, setIsMobile] = useState(false); + + useEffect(() => { + setIsMobile(isClientMediumMobile || isClientMobile || isClientSmallMobile); + }, [isClientMediumMobile, isClientMobile, isClientSmallMobile]); + + if (!isMobile) { + return ; + } + + return ( + <> + + + + + + ); } diff --git a/src/components/CalledMobile/index.tsx b/src/components/CalledMobile/index.tsx index 51f70123..0513ec6c 100644 --- a/src/components/CalledMobile/index.tsx +++ b/src/components/CalledMobile/index.tsx @@ -9,6 +9,7 @@ import { StatusText, IconeSelo, IssueWrapper, + InfoLabel, } from "./styles"; import { Selo } from "@/assets/Icons"; import { IssueMobileProps } from "@/assets"; @@ -22,7 +23,7 @@ export const IssueMobile = ({ borderColor, }: IssueMobileProps) => { return ( - + {isUpdated && ( @@ -38,11 +39,11 @@ export const IssueMobile = ({ - Aberto em: + Aberto em: {date} - Status + Status {$status} diff --git a/src/components/CalledMobile/styles.ts b/src/components/CalledMobile/styles.ts index 2f5b2f55..3e591392 100644 --- a/src/components/CalledMobile/styles.ts +++ b/src/components/CalledMobile/styles.ts @@ -1,4 +1,5 @@ import { Row } from "@/styles"; +import Link from "next/link"; import styled, { css } from "styled-components"; type ContainerStyleProps = { @@ -12,8 +13,8 @@ export const IconeSelo = styled.section` position: relative; width: 1rem; z-index: 2; - top: 15px; - left: 5px; + top: 15px; + left: 5px; & > svg { position: absolute; @@ -23,7 +24,7 @@ export const IconeSelo = styled.section` } `; -export const IssueWrapper = styled.div` +export const IssueWrapper = styled(Link)` width: 100%; height: fit-content; padding-left: 0.3rem; @@ -119,3 +120,7 @@ export const StatusText = styled.text` letter-spacing: 0.06em; color: ${({ theme }) => theme.colors.neutral.inverted}; `; + +export const InfoLabel = styled.label` + color: ${({ theme }) => theme.colors.neutral.inverted}; +`; diff --git a/src/components/Fieldset/index.tsx b/src/components/Fieldset/index.tsx new file mode 100644 index 00000000..74f70c32 --- /dev/null +++ b/src/components/Fieldset/index.tsx @@ -0,0 +1,28 @@ +import { Fieldset, Legend, LegendText } from "./styles"; + +export type FieldsetProps = { + children: React.ReactNode; + labelText: string; + width?: string; + height?: string; +}; + +const CustomFieldset = ({ + children, + labelText, + height, + width, +}: FieldsetProps) => { + return ( +
+ + {labelText} + + {children} +
+ ); +}; + +export { CustomFieldset }; diff --git a/src/components/Fieldset/styles.ts b/src/components/Fieldset/styles.ts new file mode 100644 index 00000000..a50931e3 --- /dev/null +++ b/src/components/Fieldset/styles.ts @@ -0,0 +1,35 @@ +import styled from "styled-components"; + +export const Fieldset = styled.fieldset<{ width?: string; height?: string }>` + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 4px 12px; + width: ${({ width }) => width ?? "fit-content"}; + height: ${({ height }) => height ?? "fit-content"}; + border-radius: 4px; + border: 1px solid ${({ theme }) => theme.colors.neutral["15"]}; + flex: none; + order: 0; + align-self: stretch; + flex-grow: 0; + background-color: none; +`; + +export const Legend = styled.legend` + padding: 0px 4px 0px 4px; +`; + +export const LegendText = styled.span` + font-style: normal; + font-weight: 400; + font-size: 12px; + line-height: 16px; + + letter-spacing: 0.4px; + + color: #2b4417; + flex: none; + order: 0; + flex-grow: 0; +`; diff --git a/src/components/FildestInput/index.tsx b/src/components/FildestInput/index.tsx index b61bc37a..e3be39b6 100644 --- a/src/components/FildestInput/index.tsx +++ b/src/components/FildestInput/index.tsx @@ -12,7 +12,7 @@ export interface ILegendProps { minLength?: number; value?: string; onChange?: ChangeEventHandler; - source?: any; + source?: string; imgDescription?: string; hasImage?: boolean; border?: string; diff --git a/src/components/FildsetTextArea/index.tsx b/src/components/FildsetTextArea/index.tsx deleted file mode 100644 index 1a25ea92..00000000 --- a/src/components/FildsetTextArea/index.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { ChangeEventHandler, useState } from "react"; -import { Fildset, TextArea, Legend, LegendText } from "./styles"; - -interface ILegendProps { - legendText?: string; - width?: string; - placeholder?: string; - height?: string; - value?: string; - onChange?: ChangeEventHandler; -} - -export const FildsetTextArea = ({ - legendText, - placeholder, - width, - height, - value, - onChange, -}: ILegendProps) => { - return ( - - - {legendText} - - - - ); -}; diff --git a/src/components/SelectOption/styles.ts b/src/components/SelectOption/styles.ts deleted file mode 100644 index 28be7c50..00000000 --- a/src/components/SelectOption/styles.ts +++ /dev/null @@ -1,75 +0,0 @@ -import styled from "styled-components"; - -export const TextArea = styled.select` - width: 100%; - height: 100%; - outline: 0; - border: none; - font-family: "Roboto"; - font-style: normal; - font-weight: 400; - font-size: 16px; - line-height: 24px; - align-items: center; - letter-spacing: 0.5px; - resize: none; - background: transparent; - color: #2b4417; - padding: 4px; -`; - -interface FieldsetProps { - width?: string; - height?: string; -} -export const Fildset = styled.fieldset` - display: flex; - flex-direction: column; - align-items: flex-start; - padding: 0px; - width: ${({ width }) => width || "366px"}; - height: ${({ height }) => height || "55px"}; - border-radius: 4px; - border: 1px solid #49454f; - flex: none; - order: 0; - align-self: stretch; - flex-grow: 0; - padding-left: 1rem; - padding-right: 1.6rem; - background-color: transparent; - - option { - display: flex; - align-items: center; - background-color: #ebf6e3; - border-radius: 0; - width: 56px; - border: none; - font-size: 13px; - } - - option[value=""][disabled] { - display: none; - } - -`; - -export const Legend = styled.legend` - padding: 0px 4px 0px 4px; -`; - -export const LegendText = styled.span` - font-family: "roboto"; - font-style: normal; - font-weight: 400; - font-size: 12px; - line-height: 16px; - - letter-spacing: 0.4px; - - color: #2b4417; - flex: none; - order: 0; - flex-grow: 0; -`; diff --git a/src/components/Buttons/AddNewIssueButton/index.tsx b/src/components/common/Buttons/AddNewIssueButton/index.tsx similarity index 90% rename from src/components/Buttons/AddNewIssueButton/index.tsx rename to src/components/common/Buttons/AddNewIssueButton/index.tsx index 1bfe3d60..c14451bf 100644 --- a/src/components/Buttons/AddNewIssueButton/index.tsx +++ b/src/components/common/Buttons/AddNewIssueButton/index.tsx @@ -5,7 +5,7 @@ import { ButtonNewCalled } from "./styles"; interface AddNewIssueButtonStyleProps { iconColor?: string; iconSize?: number; - backgroundColor?: string; + $backgroundColor?: string; borderRadius?: number; hasShadow?: boolean; } diff --git a/src/components/Buttons/AddNewIssueButton/styles.ts b/src/components/common/Buttons/AddNewIssueButton/styles.ts similarity index 84% rename from src/components/Buttons/AddNewIssueButton/styles.ts rename to src/components/common/Buttons/AddNewIssueButton/styles.ts index 784d2d21..5b6d7691 100644 --- a/src/components/Buttons/AddNewIssueButton/styles.ts +++ b/src/components/common/Buttons/AddNewIssueButton/styles.ts @@ -9,7 +9,7 @@ export const ButtonNewCalled = styled.button` padding: 0; width: ${({ size }) => size || "3.5rem"}; height: ${({ size }) => size || "3.5rem"}; - background-color: ${({ styles }) => styles?.backgroundColor || "#ebf6e3"}; + background-color: ${({ styles }) => styles?.$backgroundColor || "#ebf6e3"}; ${({ styles }) => styles?.hasShadow && css` diff --git a/src/components/Buttons/BackButton/index.tsx b/src/components/common/Buttons/BackButton/index.tsx similarity index 91% rename from src/components/Buttons/BackButton/index.tsx rename to src/components/common/Buttons/BackButton/index.tsx index 0ed36b35..ee686d4c 100644 --- a/src/components/Buttons/BackButton/index.tsx +++ b/src/components/common/Buttons/BackButton/index.tsx @@ -16,7 +16,7 @@ export const BackButton = ({ const router = useRouter(); return ( router.back()}> - {actionText === "Login" ? ( + {actionText !== "Login" ? ( ` font-style: normal; font-weight: ${({ fontWeight }) => fontWeight || 500}; - font-size: 1.6rem; + font-size: 1.2rem; display: flex; line-height: 36px; align-items: center; diff --git a/src/components/Buttons/Button/index.tsx b/src/components/common/Buttons/Button/index.tsx similarity index 60% rename from src/components/Buttons/Button/index.tsx rename to src/components/common/Buttons/Button/index.tsx index 93928b65..c8dc8a2b 100644 --- a/src/components/Buttons/Button/index.tsx +++ b/src/components/common/Buttons/Button/index.tsx @@ -6,7 +6,7 @@ export interface CustomButtonProps text?: string; color?: string; $backgroundColor?: string; - borderColor?: string; + $borderColor?: string; onClick?: () => void; disabled?: boolean; icon?: StaticImageData; @@ -14,13 +14,30 @@ export interface CustomButtonProps alt?: string; width?: string | number; height?: string | number; + mode?: "filled" | "outlined"; } - +/** + * Botao customizado + * + *@param text - Texto do botao + *@param color - Cor do texto + *@param $backgroundColor - Cor do fundo + *@param $borderColor - Cor da borda + *@param onClick - Funcao de click + *@param disabled - Desabilita o botao + *@param icon - Icone do botao + *@param iconSize - Tamanho do icone + *@param alt - Texto alternativo do icone + *@param width - Largura do botao + *@param height - Altura do botao + *@param mode - Modo do botao + * + */ export const CustomButton = ({ text = "button", $backgroundColor = "grey", color = "black", - borderColor, + $borderColor = "black", disabled = false, onClick, icon, @@ -28,15 +45,17 @@ export const CustomButton = ({ alt, width, height, + mode = "filled", ...props }: CustomButtonProps) => { return ( ` display: flex; justify-content: center; align-items: center; - background-color: ${({ $backgroundColor, theme }) => - $backgroundColor ? $backgroundColor : theme.colors.green[185]}; - color: ${({ color, theme }) => (color ? color : theme.colors.neutral.white)}; + font-size: 1rem; border-radius: 10rem; - border: ${({ borderColor }) => - borderColor ? `1px solid ${borderColor}` : "none"}; + padding: 10px 24px; width: ${({ width }) => (width ? width : "100%")}; height: ${({ height }) => (height ? height : "100%")}; - font-size: 1.4rem; - ${({ disabled }) => + + color: ${({ color, theme }) => (color ? color : theme.colors.neutral.white)}; + + border: ${({ $borderColor, mode }) => + $borderColor && mode === "outlined" ? `1px solid ${$borderColor}` : "none"}; + + ${({ disabled, mode }) => + disabled && + mode === "outlined" && + css` + border: 1px solid #bfbfbf; + pointer-events: none; + `}; + + background-color: ${({ $backgroundColor, mode, theme }) => + $backgroundColor && mode === "filled" + ? $backgroundColor + : theme.colors.green[185]}; + + ${({ disabled, mode }) => disabled && + mode === "filled" && css` background-color: #e5e6e6; pointer-events: none; @@ -36,5 +52,7 @@ export const ButtonComponent = styled.button<{ color?: string }>` &:disabled { color: #1c1b1f; opacity: 0.5; + pointer-events: none; + cursor: default; } `; diff --git a/src/components/Buttons/IconButton/index.tsx b/src/components/common/Buttons/IconButton/index.tsx similarity index 100% rename from src/components/Buttons/IconButton/index.tsx rename to src/components/common/Buttons/IconButton/index.tsx diff --git a/src/components/Buttons/IconButton/styles.tsx b/src/components/common/Buttons/IconButton/styles.tsx similarity index 90% rename from src/components/Buttons/IconButton/styles.tsx rename to src/components/common/Buttons/IconButton/styles.tsx index 221cee49..adb656a5 100644 --- a/src/components/Buttons/IconButton/styles.tsx +++ b/src/components/common/Buttons/IconButton/styles.tsx @@ -7,7 +7,7 @@ interface CustomButtonProps { color?: string; width?: string; height?: string; - onHover?: React.MouseEventHandler | undefined; + onHover?: React.MouseEventHandler; } const IconButtonWrapper = styled.div``; diff --git a/src/components/Buttons/index.tsx b/src/components/common/Buttons/index.tsx similarity index 100% rename from src/components/Buttons/index.tsx rename to src/components/common/Buttons/index.tsx diff --git a/src/components/Icon/index.tsx b/src/components/common/CustomIcon/index.tsx similarity index 88% rename from src/components/Icon/index.tsx rename to src/components/common/CustomIcon/index.tsx index 68d11e53..68ba9080 100644 --- a/src/components/Icon/index.tsx +++ b/src/components/common/CustomIcon/index.tsx @@ -2,7 +2,9 @@ import { useState } from "react"; import { IconContainer, IconImage } from "./styles"; interface IconProps { + // skipcq: JS-0323 src?: any; + // skipcq: JS-0323 alternate?: any; alt?: string; color?: string; diff --git a/src/components/Icon/styles.ts b/src/components/common/CustomIcon/styles.ts similarity index 100% rename from src/components/Icon/styles.ts rename to src/components/common/CustomIcon/styles.ts diff --git a/src/components/Input/index.tsx b/src/components/common/CustomInput/index.tsx similarity index 69% rename from src/components/Input/index.tsx rename to src/components/common/CustomInput/index.tsx index 820ccc71..a6e35437 100644 --- a/src/components/Input/index.tsx +++ b/src/components/common/CustomInput/index.tsx @@ -9,8 +9,9 @@ import { SupportText, ErrorText, Label, + WarningText, } from "./styles"; -import { Icon } from ".."; +import { Icon } from "../.."; import { StaticImageData } from "next/image"; import { useState } from "react"; @@ -22,6 +23,7 @@ export interface InputStylesProps { borderColor?: string; width?: string; height?: string; + mode?: "filled" | "outlined"; placeholderColor?: string; } @@ -44,22 +46,24 @@ interface InputProps { labelText?: string; trailingButton?: ActionButton; leadingButton?: ActionButton; - type: "text" | "password" | "email" | "number" | "tel" | "search" | "url"; + type?: "text" | "password" | "email" | "number" | "tel" | "search" | "url" | "date"; style?: InputStylesProps; width?: string; height?: string; + mode?: "filled" | "outlined"; } const CustomInput = ({ type = "text", - placeholder, + placeholder = "Digite aqui", $status = "none", labelText, - errorText, + errorText = "Houve um erro, tente novamente!", onChange, style, value, warnText, + mode = "filled", leadingButton, trailingButton, width, @@ -68,8 +72,10 @@ const CustomInput = ({ const [inputType, setInputType] = useState(type); return ( - {labelText && } + {labelText && } {leadingButton && ( @@ -101,8 +107,22 @@ const CustomInput = ({ {/* */} {$status === "invalid" && {errorText}} + {$status === "warning" && {warnText}} ); }; -export { CustomInput }; +const OutlinedInput = (props: InputProps) => { + return ( + + ); +}; + +export { CustomInput, OutlinedInput }; diff --git a/src/components/common/CustomInput/styles.ts b/src/components/common/CustomInput/styles.ts new file mode 100644 index 00000000..8b07fa8e --- /dev/null +++ b/src/components/common/CustomInput/styles.ts @@ -0,0 +1,120 @@ +import { css, styled } from "styled-components"; +import { InputStylesProps } from "."; +import { Row } from "@/styles"; + +interface ContentContainerProps { + height?: string; + mode?: "filled" | "outlined"; + $status?: "valid" | "invalid" | "warning" | "none"; + backgroundColor?: string; +} + +export const InputContainer = styled.div` + width: ${({ width }) => width || "100%"}; + height: fit-content; + margin-top: 0.3rem; +`; + +export const ContentContainer = styled(Row)` + display: flex; + justify-content: center; + align-items: center; + height: ${({ height }) => height || "100%"}; + background-color: ${({ backgroundColor }) => backgroundColor}; + + ${({ mode }) => + mode === "filled" && + css` + border-radius: 4px 4px 0px 0px; + margin: 0.5rem 0rem 0.1rem 0rem; + `} + + ${({ mode, $status }) => + mode === "filled" && $status === "invalid" + ? css` + background-color: #fbdde1; + border-bottom: 0.2rem red solid; + ` + : mode === "filled" && $status === "valid" + ? css` + background-color: #ebf6e3; + border-bottom: 0.2rem #7ac143 solid; + ` + : mode === "filled" + ? css` + background-color: #e5e6e6; + ` + : css``}; + + ${({ mode }) => + mode === "outlined" && + css` + background-color: transparent; + margin: 0.5rem 0rem 0.1rem 0rem; + border-radius: 4px; + margin: -8px 0rem 0.1rem 0rem; + color: #1c1b1f; + `} + + ${({ mode, $status }) => + mode === "outlined" && $status === "invalid" + ? css` + border: 1px solid red; + ` + : mode === "outlined" && $status === "valid" + ? css` + border: 1px solid #7ac143; + ` + : mode === "outlined" + ? css` + border: 1px solid #79747e; + ` + : css``}; +`; + +export const InputComponent = styled.input` + width: 100%; + height: 100%; + border: none; + display: flex; + align-items: center; + font-size: 1rem; + color: #1c1b1f; + font-weight: 400; + outline: none; + padding: 1rem; + background-color: transparent; + ${({ type }) => + type === "date" && + css` + padding-top: 1.2rem; + `}; +`; + +export const SupportText = styled.span<{ color?: string }>` + font-size: 0.8rem; + color: ${({ color }) => color || "#1c1b1f"}; + font-weight: 500; +`; + +export const ErrorText = styled(SupportText)` + color: #b3261e; +`; + +export const WarningText = styled(SupportText)` + color: #f2994a; +`; + +export const Label = styled.label<{ mode: "filled" | "outlined" }>` + font-size: ${({ mode }) => (mode === "filled" ? "1.2rem" : "12px")}; + font-weight: 400; + color: #49454f; + + ${({ mode }) => + mode === "outlined" && + css` + margin-left: 0.4rem; + background-color: #f5f5f5; + padding: 0 0.4rem; + `} +`; diff --git a/src/components/CustomLink/index.tsx b/src/components/common/CustomLink/index.tsx similarity index 72% rename from src/components/CustomLink/index.tsx rename to src/components/common/CustomLink/index.tsx index 09e9bcd8..70043d43 100644 --- a/src/components/CustomLink/index.tsx +++ b/src/components/common/CustomLink/index.tsx @@ -3,12 +3,12 @@ import styled from "styled-components"; interface CustomLinkProps { color?: string; - flexDirection?: "row" | "column"; + $flexDirection?: "row" | "column"; } export const CustomLink = styled(Link)` display: flex; - flex-direction: ${({ flexDirection }) => flexDirection || "row"}; + flex-direction: ${({ $flexDirection }) => $flexDirection || "row"}; justify-content: center; align-items: center; text-decoration: none; diff --git a/src/components/common/CustomSelect/index.tsx b/src/components/common/CustomSelect/index.tsx new file mode 100644 index 00000000..76b87933 --- /dev/null +++ b/src/components/common/CustomSelect/index.tsx @@ -0,0 +1,64 @@ +import { ChangeEventHandler, ReactNode } from "react"; +import { SelectComponent, CustomOption } from "./styles"; +import { CustomFieldset } from "@/components/Fieldset"; + +interface OptionProps { + key: string; + value: string; + text: string; + isDisabled?: boolean; + isSelected?: boolean; +} + +interface SelectProps { + labelText: string; + width?: string; + placeholder?: string; + height?: string; + onChange?: ChangeEventHandler; + options?: OptionProps[]; + isRequired?: boolean; + multiple?: boolean; + form?: string; + name?: string; + value?: string; +} + +export const CustomSelect = ({ + labelText, + placeholder = "selecione uma opção", + width = "100%", + height = "56px", + options, + onChange, + isRequired = false, + multiple = false, + form, +}: SelectProps) => { + return ( + + + + {placeholder ?? "selecione uma opção abaixo"} + + {options?.map((option) => ( + + {option?.text} + + ))} + + + ); +}; diff --git a/src/components/common/CustomSelect/styles.ts b/src/components/common/CustomSelect/styles.ts new file mode 100644 index 00000000..1b17e736 --- /dev/null +++ b/src/components/common/CustomSelect/styles.ts @@ -0,0 +1,28 @@ +import styled from "styled-components"; + +export const SelectComponent = styled.select` + width: 100%; + height: 100%; + padding-top: 4px; + outline: 0; + border: none; + font-weight: 400; + font-size: 1rem; + line-height: 24px; + align-items: center; + letter-spacing: 0.5px; + resize: none; + background: transparent; + color: #77757b; +`; + +export const CustomOption = styled.option` + display: flex; + align-items: center; + background-color: #ebf6e3; + padding-bottom: 10px; + width: 20px; + border-radius: 0; + border: none; + font-size: 16px; +`; diff --git a/src/components/common/CustomTextArea/index.tsx b/src/components/common/CustomTextArea/index.tsx new file mode 100644 index 00000000..7ac37d03 --- /dev/null +++ b/src/components/common/CustomTextArea/index.tsx @@ -0,0 +1,38 @@ +import { ChangeEvent } from "react"; +import { TextArea } from "./styles"; +import { CustomFieldset } from "../../Fieldset"; + +interface TextAreaProps { + labelText?: string; + width?: string; + height?: string; + placeholder: string; + value?: string; + isRequired?: boolean; + onChange?: (e: ChangeEvent) => void; +} + +export const CustomTextArea = ({ + labelText, + placeholder, + width = "100%", + height = "240px", + value, + onChange, + isRequired = false, +}: TextAreaProps) => { + return ( + +