diff --git a/.github/workflows/nextjs_bundle_analysis.yml b/.github/workflows/nextjs_bundle_analysis.yml index 51e4fd512..c77840bcd 100644 --- a/.github/workflows/nextjs_bundle_analysis.yml +++ b/.github/workflows/nextjs_bundle_analysis.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: 'Next.js Bundle Analysis' on: @@ -12,24 +15,36 @@ defaults: # change this if your nextjs app does not live at the root of the repo working-directory: ./ +permissions: + contents: read # for checkout repository + actions: read # for fetching base branch bundle stats + pull-requests: write # for comments + jobs: analyze: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Set up node - uses: actions/setup-node@v1 + - name: Install Node.js + uses: actions/setup-node@v3 with: - node-version: '15.x' + node-version: 18 - name: Install dependencies uses: bahmutov/npm-install@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # If pnpm is used, you need to switch the previous step with the following one. pnpm does not create a package-lock.json + # so the step above will fail to pull dependencies + # - uses: pnpm/action-setup@v2 + # name: Install pnpm + # id: pnpm-install + # with: + # version: 7 + # run_install: true - name: Restore next build - uses: actions/cache@v2 + uses: actions/cache@v3 id: restore-build-cache env: cache-name: cache-next-build @@ -42,12 +57,7 @@ jobs: - name: Build next.js app # change this if your site requires a custom build command - run: npm run build - env: - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ANALYZE: 'true' - + run: ./node_modules/.bin/next build # Here's the first place where next-bundle-analysis' own script is used # This step pulls the raw bundle stats for the current bundle @@ -55,17 +65,11 @@ jobs: run: npx -p nextjs-bundle-analysis report - name: Upload bundle - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3 with: name: bundle path: .next/analyze/__bundle_analysis.json - - name: Upload packages analyzer - uses: actions/upload-artifact@v4 - with: - name: bundle-packages - path: .next/analyze/ - - name: Download base branch bundle stats uses: dawidd6/action-download-artifact@v2 if: success() && github.event.number @@ -91,18 +95,17 @@ jobs: if: success() && github.event.number run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare - - name: Get comment body + - name: Get Comment Body id: get-comment-body if: success() && github.event.number + # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings run: | - body=$(cat .next/analyze/__bundle_analysis_comment.txt) - body="${body//'%'/'%25'}" - body="${body//$'\n'/'%0A'}" - body="${body//$'\r'/'%0D'}" - echo ::set-output name=body::$body + echo "body<> $GITHUB_OUTPUT + echo "$(cat .next/analyze/__bundle_analysis_comment.txt)" >> $GITHUB_OUTPUT + echo EOF >> $GITHUB_OUTPUT - name: Find Comment - uses: peter-evans/find-comment@v1 + uses: peter-evans/find-comment@v2 if: success() && github.event.number id: fc with: @@ -110,14 +113,14 @@ jobs: body-includes: '' - name: Create Comment - uses: peter-evans/create-or-update-comment@v1.4.4 + uses: peter-evans/create-or-update-comment@v2 if: success() && github.event.number && steps.fc.outputs.comment-id == 0 with: issue-number: ${{ github.event.number }} body: ${{ steps.get-comment-body.outputs.body }} - name: Update Comment - uses: peter-evans/create-or-update-comment@v1.4.4 + uses: peter-evans/create-or-update-comment@v2 if: success() && github.event.number && steps.fc.outputs.comment-id != 0 with: issue-number: ${{ github.event.number }} diff --git a/lang/pt-BR.json b/lang/pt-BR.json index 03f14e217..a73e8a836 100644 --- a/lang/pt-BR.json +++ b/lang/pt-BR.json @@ -1291,6 +1291,10 @@ "defaultMessage": "para {confidence}", "description": "This text is displayed as the second line of our confidence tooltip" }, + "IldkUk": { + "defaultMessage": "Filtros", + "description": "This is the default placeholder while selecting a given value in a select menu" + }, "IoZbDV": { "defaultMessage": "Deseja excluir esse comentário?", "description": "This message appears in delete modal confirmation." diff --git a/lib/fake-api/db.task-management.json b/lib/fake-api/db.task-management.json deleted file mode 100644 index ac1e04b75..000000000 --- a/lib/fake-api/db.task-management.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "board": [ - { - "id": "1", - "title": "Tarefas Produto", - "type": "teamTasks", - "teamsIds": [ - "d6310cc8-cc17-499b-a28c-5c600dd9714a" - ], - "tasks": [ - "1", - "2", - "3", - "4", - "5" - ], - "createdAt": "2020-01-01", - "updateadAt": "2020-01-01" - }, - { - "id": "2", - "title": "Tarefas Customer Success", - "type": "teamTasks", - "teamsIds": [ - "0788abd6-4996-4224-8f24-094b2d3c0d3a" - ], - "tasks": [ - 1 - ], - "createdAt": "2020-01-01", - "updateadAt": "2020-01-01" - }, - { - "id": "3", - "title": "Tarefas Financeiro", - "type": "teamTasks", - "teamsIds": [ - "41a0de90-216d-4092-9d5f-1e889ec0a7cb" - ], - "tasks": [ - "6" - ], - "createdAt": "2020-01-01", - "updateadAt": "2020-01-01" - } - ], - "tasks": [ - { - "id": "1", - "boardId": "1", - "status": "pending", - "title": "Marcar reunião com fornecedores de camisetas", - "description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500", - "dueDate": "2023-05-12", - "initialDate": "2023-11-01", - "priority": 1, - "owner": "922ef72a-6c3c-4075-926a-3245cdeea75f", - "attachments": "http://arquivo.pdf", - "supportTeamMembers": [ - "9ce87eda-64d1-4bfb-80a5-aa7811a04ea9", - "f120ec45-150d-4e24-b99d-34df20a80c64" - ], - "tags": "COZINHA", - "nextTaskId": "2" - }, - { - "id": "2", - "boardId": "1", - "status": "pending", - "title": "Enviar mailing de cadastramento de conferencias e eventos", - "description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500", - "dueDate": "2023-12-12", - "initialDate": "2023-11-01", - "priority": 3, - "owner": "9ce87eda-64d1-4bfb-80a5-aa7811a04ea9", - "attachments": "http://arquivo.pdf", - "supportTeamMembers": [ - "b159ef12-9062-49c6-8afc-372e8848fb15" - ], - "tags": "COZINHA", - "nextTaskId": "" - }, - { - "id": "3", - "boardId": "1", - "status": "toDo", - "title": "Entrar em contato com empresa XYZ de eventos", - "description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500", - "dueDate": "2023-10-12", - "initialDate": "2023-11-01", - "priority": 4, - "owner": "9ce87eda-64d1-4bfb-80a5-aa7811a04ea9", - "attachments": "http://arquivo.pdf", - "supportTeamMembers": [ - "b159ef12-9062-49c6-8afc-372e8848fb15" - ], - "tags": "COZINHA", - "nextTaskId": "" - }, - { - "id": "4", - "boardId": "1", - "status": "doing", - "title": "Marcar reunião com fornecedores de camisetas", - "description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500", - "dueDate": "2023-02-21", - "initialDate": "2023-11-01", - "priority": 1, - "owner": "9ce87eda-64d1-4bfb-80a5-aa7811a04ea9", - "attachments": "http://arquivo.pdf", - "supportTeamMembers": [ - "b159ef12-9062-49c6-8afc-372e8848fb15" - ], - "tags": "COZINHA", - "nextTaskId": "" - }, - { - "id": "5", - "boardId": "1", - "status": "done", - "title": "Enviar mailing de cadastramento de conferencias e eventos", - "description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500", - "dueDate": "2023-02-21", - "initialDate": "2023-11-01", - "priority": 2, - "owner": "f120ec45-150d-4e24-b99d-34df20a80c64", - "attachments": "http://arquivo.pdf", - "supportTeamMembers": [ - "b159ef12-9062-49c6-8afc-372e8848fb15", - "9ce87eda-64d1-4bfb-80a5-aa7811a04ea9" - ], - "tags": "COZINHA", - "nextTaskId": "" - }, - { - "id": "6", - "boardId": "3", - "status": "doing", - "title": "Enviar mailing de cadastramento de conferencias e eventos", - "description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500", - "dueDate": "2023-12-01", - "initialDate": "2023-11-01", - "priority": 3, - "owner": "b159ef12-9062-49c6-8afc-372e8848fb15", - "attachments": "http://arquivo.pdf", - "supportTeamMembers": [ - "f120ec45-150d-4e24-b99d-34df20a80c64", - "9ce87eda-64d1-4bfb-80a5-aa7811a04ea9", - "922ef72a-6c3c-4075-926a-3245cdeea75f" - ], - "tags": "COZINHA", - "nextTaskId": "" - } - ] -} diff --git a/lib/fake-api/routes.json b/lib/fake-api/routes.json deleted file mode 100644 index db530c160..000000000 --- a/lib/fake-api/routes.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "/board/:teamId": "/board?teamsIds[0]=:teamId&_embed=tasks" -} diff --git a/public/icons/check.svg b/public/icons/check.svg new file mode 100644 index 000000000..42829d01f --- /dev/null +++ b/public/icons/check.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Base/KanbanTaskCard/kanban-task-card-metadata.tsx b/src/components/Base/KanbanTaskCard/kanban-task-card-metadata.tsx index b5f6f3d0d..d3cc8d4ac 100644 --- a/src/components/Base/KanbanTaskCard/kanban-task-card-metadata.tsx +++ b/src/components/Base/KanbanTaskCard/kanban-task-card-metadata.tsx @@ -9,7 +9,7 @@ import ClockIcon from 'src/components/Icon/Clock' import LowPriorityIcon from 'src/components/Icon/LowPriorityIcon' import MediumPriorityIcon from 'src/components/Icon/MediumPriorityIcon' import { User } from 'src/components/User/types' -import { TASK_STATUS } from 'src/services/task-management/task-management.service' +import { TASK_STATUS } from 'src/services/task-management/@types/task-status.enum' import selectUser from 'src/state/recoil/user/selector' import { TaskPriority } from './kanban-task-card-root' diff --git a/src/components/Cycle/hooks/use-get-team-cycle.ts b/src/components/Cycle/hooks/use-get-team-cycle.ts index 60c259970..a4845baf4 100644 --- a/src/components/Cycle/hooks/use-get-team-cycle.ts +++ b/src/components/Cycle/hooks/use-get-team-cycle.ts @@ -13,7 +13,7 @@ export function useTeamCycleData(teamId: string) { queryKey: [`${MODULE}:${ACTION}:${teamId}`], queryFn: async () => { const { cycle } = await servicesPromise - const data = await cycle.getCycleTeam(teamId) + const data = await cycle.getTeamCycle(teamId) return data }, }) diff --git a/src/components/KeyResult/Single/Sections/Checklist/ActionButtons/create-task-in-kr.tsx b/src/components/KeyResult/Single/Sections/Checklist/ActionButtons/create-task-in-kr.tsx index 797eac597..441ab054c 100644 --- a/src/components/KeyResult/Single/Sections/Checklist/ActionButtons/create-task-in-kr.tsx +++ b/src/components/KeyResult/Single/Sections/Checklist/ActionButtons/create-task-in-kr.tsx @@ -6,9 +6,9 @@ import { useRecoilValue } from 'recoil' import { EditableInputField } from 'src/components/Base' import { PlusOutline } from 'src/components/Icon' +import { useAddTask } from 'src/components/KeyResult/hooks/use-add-task-new' import { NewTask } from 'src/components/Task/types' -import { useAddTask } from 'src/components/TaskManagement/hooks/use-add-task-new' -import { TASK_STATUS } from 'src/services/new-task-management/@types/task-status.enum' +import { TASK_STATUS } from 'src/services/task-management/@types/task-status.enum' import { keyResultAtomFamily } from 'src/state/recoil/key-result' import meAtom from 'src/state/recoil/user/me' diff --git a/src/components/KeyResult/Single/Sections/Checklist/ActionButtons/delete-task.tsx b/src/components/KeyResult/Single/Sections/Checklist/ActionButtons/delete-task.tsx index f779998d4..ee6bb5246 100644 --- a/src/components/KeyResult/Single/Sections/Checklist/ActionButtons/delete-task.tsx +++ b/src/components/KeyResult/Single/Sections/Checklist/ActionButtons/delete-task.tsx @@ -2,7 +2,7 @@ import React, { Ref } from 'react' import { useIntl } from 'react-intl' import { DeleteButton } from 'src/components/Base/Button/delete-button' -import { useDeleteTaskByKr } from 'src/components/TaskManagement/hooks/use-delete-tasks' +import { useDeleteTaskByKr } from 'src/components/KeyResult/hooks/use-delete-tasks' import messages from './messages' diff --git a/src/components/KeyResult/Single/Sections/Checklist/checklist.tsx b/src/components/KeyResult/Single/Sections/Checklist/checklist.tsx index 910dce4a6..832a58051 100644 --- a/src/components/KeyResult/Single/Sections/Checklist/checklist.tsx +++ b/src/components/KeyResult/Single/Sections/Checklist/checklist.tsx @@ -2,8 +2,8 @@ import { Stack, StyleProps } from '@chakra-ui/react' import styled from '@emotion/styled' import React, { useRef } from 'react' -import { Task } from 'src/services/new-task-management/@types/task.type' import { TaskSummary } from 'src/services/okr/key-result/@types' +import { Task } from 'src/services/task-management/@types/task.type' import { CreateTaskButton } from './ActionButtons/create-task-in-kr' import { InlineTaskList } from './inline-tasklist' diff --git a/src/components/KeyResult/Single/Sections/Checklist/hooks/use-delete-task.ts b/src/components/KeyResult/Single/Sections/Checklist/hooks/use-delete-task.ts index 995e77e68..320e8b37b 100644 --- a/src/components/KeyResult/Single/Sections/Checklist/hooks/use-delete-task.ts +++ b/src/components/KeyResult/Single/Sections/Checklist/hooks/use-delete-task.ts @@ -12,8 +12,8 @@ export const useDeleteTask = () => { return useMutation({ mutationFn: async ({ taskId }: { taskId: string }) => { - const { newTaskManagement } = await servicesPromise - return newTaskManagement.removeTask(taskId) + const { taskManagement } = await servicesPromise + return taskManagement.removeTask(taskId) }, onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: [`${MODULE}:${ACTION}:${variables.taskId}`] }) diff --git a/src/components/KeyResult/Single/Sections/Checklist/hooks/use-update-task.ts b/src/components/KeyResult/Single/Sections/Checklist/hooks/use-update-task.ts index d2a3142cc..b3f116c53 100644 --- a/src/components/KeyResult/Single/Sections/Checklist/hooks/use-update-task.ts +++ b/src/components/KeyResult/Single/Sections/Checklist/hooks/use-update-task.ts @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query' import { useContext } from 'react' import { ServicesContext } from 'src/components/Base/ServicesProvider/services-provider' -import { TaskUpdate } from 'src/services/new-task-management/@types/task-update.type' +import { TaskUpdate } from 'src/services/task-management/@types/task-update.type' export function useUpdateTask({ userId }: { userId: string }) { const { servicesPromise } = useContext(ServicesContext) @@ -10,8 +10,8 @@ export function useUpdateTask({ userId }: { userId: string }) { const updateTaskMutate = useMutation({ mutationFn: async ({ taskId, data }: { taskId: string; data: Partial }) => { - const { newTaskManagement } = await servicesPromise - const response = await newTaskManagement.updateTask(taskId, data) + const { taskManagement } = await servicesPromise + const response = await taskManagement.updateTask(taskId, data) return response }, onSuccess: (_data, _variables) => { diff --git a/src/components/KeyResult/Single/Sections/Checklist/inline-tasklist.tsx b/src/components/KeyResult/Single/Sections/Checklist/inline-tasklist.tsx index 123bbe451..be535cab9 100644 --- a/src/components/KeyResult/Single/Sections/Checklist/inline-tasklist.tsx +++ b/src/components/KeyResult/Single/Sections/Checklist/inline-tasklist.tsx @@ -22,9 +22,9 @@ import { useRecoilValue } from 'recoil' import { EditableInputField } from 'src/components/Base' import { NamedAvatar } from 'src/components/User' import { AllReachableUsers } from 'src/components/User/AllReachableUsers/wrapper' -import { TASK_STATUS } from 'src/services/new-task-management/@types/task-status.enum' -import { Task } from 'src/services/new-task-management/@types/task.type' import { TaskSummary } from 'src/services/okr/key-result/@types' +import { TASK_STATUS } from 'src/services/task-management/@types/task-status.enum' +import { Task } from 'src/services/task-management/@types/task.type' import meAtom from 'src/state/recoil/user/me' import { DeleteTaskButton } from './ActionButtons/delete-task' diff --git a/src/components/KeyResult/Single/Sections/Checklist/wrapper.tsx b/src/components/KeyResult/Single/Sections/Checklist/wrapper.tsx index d5f94b75d..ae9064c21 100644 --- a/src/components/KeyResult/Single/Sections/Checklist/wrapper.tsx +++ b/src/components/KeyResult/Single/Sections/Checklist/wrapper.tsx @@ -7,9 +7,9 @@ import { useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil' import { IntlLink } from 'src/components/Base' import { KeyResult } from 'src/components/KeyResult/types' -import { useTeamTasksData } from 'src/components/TaskManagement/hooks/new-task/use-get-team-tasks' -import { TASK_STATUS } from 'src/services/new-task-management/@types/task-status.enum' -import { Task } from 'src/services/new-task-management/@types/task.type' +import { useTeamTasksData } from 'src/components/TaskManagement/hooks/use-get-team-tasks' +import { TASK_STATUS } from 'src/services/task-management/@types/task-status.enum' +import { Task } from 'src/services/task-management/@types/task.type' import { keyResultAtomFamily } from 'src/state/recoil/key-result' import buildPartialSelector from 'src/state/recoil/key-result/build-partial-selector' import { diff --git a/src/components/KeyResult/Single/Sections/Owner/support-team-field.tsx b/src/components/KeyResult/Single/Sections/Owner/support-team-field.tsx index 59775891b..e1cbfa756 100644 --- a/src/components/KeyResult/Single/Sections/Owner/support-team-field.tsx +++ b/src/components/KeyResult/Single/Sections/Owner/support-team-field.tsx @@ -10,7 +10,7 @@ import GET_KEY_RESULTS_HIGHLIGHTS from 'src/components/Page/Team/Highlights/get- import GET_NO_RELATED_MEMBERS from 'src/components/Page/Team/Highlights/hooks/getNoRelatedMembers/get-no-related-members.gql' import { User } from 'src/components/User/types' import { Except } from 'src/helpers/except' -import { Task } from 'src/services/new-task-management/@types/task.type' +import { Task } from 'src/services/task-management/@types/task.type' import { keyResultAtomFamily } from 'src/state/recoil/key-result' import { ownersAndSupportTeamTaskAtom } from 'src/state/recoil/task-management/board/owners-and-support-team-task' import { taskSupportTeamAtom } from 'src/state/recoil/task-management/drawers/task-drawer/task-support-team' diff --git a/src/components/TaskManagement/hooks/use-add-task-new.ts b/src/components/KeyResult/hooks/use-add-task-new.ts similarity index 75% rename from src/components/TaskManagement/hooks/use-add-task-new.ts rename to src/components/KeyResult/hooks/use-add-task-new.ts index 2f64fa1fb..b62fa9f5b 100644 --- a/src/components/TaskManagement/hooks/use-add-task-new.ts +++ b/src/components/KeyResult/hooks/use-add-task-new.ts @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query' import { useContext } from 'react' import { ServicesContext } from 'src/components/Base/ServicesProvider/services-provider' -import { TaskInsert } from 'src/services/new-task-management/new-task-management.service' +import { TaskInsert } from 'src/services/task-management/task-management.service' export function useAddTask() { const { servicesPromise } = useContext(ServicesContext) @@ -10,8 +10,8 @@ export function useAddTask() { const addTaskToKrMutate = useMutation({ mutationFn: async (data: TaskInsert) => { - const { newTaskManagement } = await servicesPromise - const response = await newTaskManagement.addTask(data) + const { taskManagement } = await servicesPromise + const response = await taskManagement.addTask(data) return response }, onSuccess: (_data, _variables) => { diff --git a/src/components/TaskManagement/hooks/use-delete-tasks.ts b/src/components/KeyResult/hooks/use-delete-tasks.ts similarity index 77% rename from src/components/TaskManagement/hooks/use-delete-tasks.ts rename to src/components/KeyResult/hooks/use-delete-tasks.ts index a40841018..48ccbc83f 100644 --- a/src/components/TaskManagement/hooks/use-delete-tasks.ts +++ b/src/components/KeyResult/hooks/use-delete-tasks.ts @@ -8,8 +8,8 @@ export const useDeleteTaskByKr = () => { return useMutation({ mutationFn: async ({ taskID }: { taskID: string }) => { - const { newTaskManagement } = await servicesPromise - return newTaskManagement.removeTask(taskID) + const { taskManagement } = await servicesPromise + return taskManagement.removeTask(taskID) }, }) } diff --git a/src/components/KeyResult/hooks/use-get-team-key-result.ts b/src/components/KeyResult/hooks/use-get-team-key-result.ts index d3c75d1d6..ec51e86d9 100644 --- a/src/components/KeyResult/hooks/use-get-team-key-result.ts +++ b/src/components/KeyResult/hooks/use-get-team-key-result.ts @@ -6,14 +6,14 @@ import { ServicesContext } from 'src/components/Base/ServicesProvider/services-p const MODULE = 'KeyResult' const ACTION = 'getAllTeamKR' -export function useTeamKRData(teamId: string, objectiveId: string) { +export function useTeamKRData(teamId: string) { const { servicesPromise } = useContext(ServicesContext) const query = useQuery({ queryKey: [`${MODULE}:${ACTION}:${teamId}`], queryFn: async () => { const { keyResult } = await servicesPromise - const data = await keyResult.getKeyResultTeam(teamId, objectiveId) + const data = await keyResult.getKeyResultTeam(teamId) return data }, }) diff --git a/src/components/Page/Team/Tabs/BoardFilters/filters.module.css b/src/components/Page/Team/Tabs/BoardFilters/filters.module.css new file mode 100644 index 000000000..c936a09ea --- /dev/null +++ b/src/components/Page/Team/Tabs/BoardFilters/filters.module.css @@ -0,0 +1,147 @@ +.modal_button { + display: flex; + align-items: baseline; + color: var(--chakra-colors-brand-500); + border: 1px solid var(--chakra-colors-brand-200); + font-weight: 500; + font-size: 15px; + border-radius: 4px; + padding: 5px 11px; + margin-right: 10px; + transition: 300ms; +} + +.modal_text { + margin: 0; + margin-right: 5px; +} + +.modal_content { + position: absolute; + background-color: #fff; + width: 170px; + border: 1px solid var(--chakra-colors-new-gray-200); + display: flex; + flex-direction: column; + padding: 5px; + border-radius: 4px; + transition: 300ms; + box-shadow: 0px 5px 10px 5px #B5C0DB1A; + z-index: 9; +} + +.modal_inner_button { + display: flex; + width: 100%; + padding: 10px; + font-size: 14px; + font-weight: 450; + align-items: center; + justify-content: space-between; + border-radius: 4px; +} + +.modal_inner_button_text { + color: var(--chakra-colors-gray-500); +} + +.sub_modal_content { + position: absolute; + display: flex; + flex-direction: column; + top: 15px; + left: 100%; + min-width: 225px; + max-height: 350px; + margin-left: 10px; + padding: 10px; + background-color: #fff; + border: 1px solid var(--chakra-colors-new-gray-200); + overflow: auto; +} + +.sub_modal_title { + padding: 0 8px; + font-weight: 450; + font-size: 12px; + color: #8193AB; +} + +.checkbox { + display: inline-block; + margin: 15px 10px; + cursor: pointer; +} + +.checkbox input { + display: none; +} + +.checkbox span { + position: relative; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; /* Limita a 2 linhas */ + overflow: hidden; + text-overflow: ellipsis; + min-height: 25px; + line-height: 18px; + font-weight: 450; + font-size: 14px; + /* Adicione padding-left para compensar a largura do :before */ + padding-left: 34px; +} + +.checkbox span:before, +.checkbox span:after { + content: ''; +} + +.checkbox span:before { + border: 1px solid var(--chakra-colors-gray-100); + width: 24px; + height: 24px; + position: absolute; + left: 0; + top: 0; + border-radius: 5px; +} + +.checkbox span:hover:before { + border-color: var(--chakra-colors-brand-500); + transition: 300ms; +} + +.checkbox span:after { + background: var(--chakra-colors-brand-500); + width: 24px; + height: 24px; + border-radius: 5px; + position: absolute; + left: 0; + top: 0; + transition: 300ms; + opacity: 0; + content: ''; /* Precisa ser vazio se usar background-image */ + background-image: url('/icons/check.svg'); /* Ou .png */ + background-size: auto; /* Garante que a imagem se ajuste */ + background-repeat: no-repeat; + background-position: center; +} + +.checkbox input:checked+span:after { + opacity: 1; +} + +.no_kr_text { + color: var(--chakra-colors-gray-500); + text-align: center; + padding: 20px 0; +} + +.divider { + margin: 8px 0; + width: 100%; + border: 1px solid #F3F5FA; + height: 1px +} diff --git a/src/components/Page/Team/Tabs/BoardFilters/index.tsx b/src/components/Page/Team/Tabs/BoardFilters/index.tsx new file mode 100644 index 000000000..9f3921c03 --- /dev/null +++ b/src/components/Page/Team/Tabs/BoardFilters/index.tsx @@ -0,0 +1,395 @@ +import { Spinner } from '@chakra-ui/react' +import { useRouter } from 'next/router' +import React, { ChangeEvent, useEffect, useState } from 'react' +import { useIntl } from 'react-intl' + +import { SearchBar } from 'src/components/Base/SearchBar/wrapper' +import ChevronDownIcon from 'src/components/Icon/ChevronDown' +import { useTeamKRData } from 'src/components/KeyResult/hooks/use-get-team-key-result' +import { useGetTeamCyclesDate } from 'src/components/TaskManagement/hooks/use-get-team-cycles-date' + +import styles from './filters.module.css' +import messages from './messages' + +interface BoardFiltersProperties { + teamId: string +} + +interface CycleFilter { + year: string | undefined + quarter: string | undefined +} + +interface FiltersData { + kr: string | undefined + cycle: CycleFilter | undefined + showDone: string | undefined +} + +interface MenuController { + isModalOpen: boolean + isKrOpen: boolean + isCycleOpen: boolean + isDoneOpen: boolean +} + +export const BoardFilters = ({ teamId }: BoardFiltersProperties) => { + const intl = useIntl() + const router = useRouter() + + const [cycleYears, setCycleYears] = useState>() + const defaultCycle = { + year: new Date().getFullYear().toString(), + quarter: Math.ceil((new Date().getMonth() + 1) / 3).toString(), + } + + const [filterData, setFilterData] = useState({ + kr: undefined, + cycle: { + year: defaultCycle.year, + quarter: defaultCycle.quarter, + }, + showDone: undefined, + }) + + const [modalController, setModalController] = useState({ + isModalOpen: false, + isKrOpen: false, + isCycleOpen: false, + isDoneOpen: false, + }) + + const handleAction = (modal: string) => { + switch (modal) { + case 'modal': + setModalController((previousValue) => { + return { + ...previousValue, + isModalOpen: !previousValue.isModalOpen, + isKrOpen: previousValue.isModalOpen ? previousValue.isKrOpen : false, + isCycleOpen: previousValue.isModalOpen ? previousValue.isCycleOpen : false, + isDoneOpen: previousValue.isModalOpen ? previousValue.isDoneOpen : false, + } + }) + break + case 'kr': + setModalController((previousValue) => { + return { + ...previousValue, + isKrOpen: !previousValue.isKrOpen, + isCycleOpen: false, + isDoneOpen: false, + } + }) + break + case 'cycle': + setModalController((previousValue) => { + return { + ...previousValue, + isCycleOpen: !previousValue.isCycleOpen, + isKrOpen: false, + isDoneOpen: false, + } + }) + break + case 'done': + setModalController((previousValue) => { + return { + ...previousValue, + isDoneOpen: !previousValue.isDoneOpen, + isKrOpen: false, + isCycleOpen: false, + } + }) + break + default: + break + } + } + + const checkValue = (oldValue: string | undefined, newValue: string) => { + return oldValue === newValue ? undefined : newValue + } + + const handleChange = (filter: string) => (event: ChangeEvent) => { + setFilterData((previousValue) => { + const data = event.target.value + if (filter === 'kr') { + handleQuery('key_result_id__id', checkValue(previousValue.kr, data)) + return { + ...previousValue, + kr: checkValue(previousValue.kr, data), + } + } + + if (filter === 'cycleYear') { + handleQuery('cy', `${data} + ${previousValue.cycle?.quarter ?? ''}`) + return { + ...previousValue, + cycle: { + year: checkValue(previousValue.cycle?.year, data), + quarter: previousValue.cycle?.quarter, + }, + } + } + + if (filter === 'cycleQuarter') { + handleQuery( + 'cy', + `${previousValue.cycle?.year ?? ''} + ${ + checkValue(previousValue.cycle?.quarter, data) ?? '' + }`, + ) + return { + ...previousValue, + cycle: { + quarter: checkValue(previousValue.cycle?.quarter, data), + year: previousValue.cycle?.year, + }, + } + } + + if (filter === 'showDone') { + handleQuery('show_done', data) + + return { + ...previousValue, + showDone: data === 'none' ? undefined : data, + } + } + + return previousValue + }) + } + + const { data: KeyResultData, isFetching: krFetching } = useTeamKRData(teamId) + const { data: cycles } = useGetTeamCyclesDate(teamId) + + const handleQuery = (key: string, newValue?: string) => { + router.query[key] = newValue === 'none' ? undefined : newValue + router.push(router, undefined, { shallow: true }) + return true + } + + useEffect(() => { + if (cycles) { + const result: Record = {} + for (const item of cycles) { + if (!result[item.year]) { + result[item.year] = [] + } + + result[item.year].push(item.quarter) + } + + setCycleYears(result) + } + }, [cycles]) + + const checkQuery = (index: string) => { + return router.query[index] === '' || router.query[index] === 'none' + ? undefined + : (router.query[index] as string) + } + + useEffect(() => { + const cycle = checkQuery('cy') + + setFilterData({ + kr: checkQuery('key_result_id__id'), + cycle: { + year: + cycle && cycle.length > 0 ? cycle.split('+')[0].replace(/\s/g, '') : defaultCycle.year, + quarter: + cycle && cycle.length > 1 ? cycle.split('+')[1].replace(/\s/g, '') : defaultCycle.quarter, + }, + showDone: checkQuery('show_done'), + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [router.query]) + + return ( +
+ + {modalController.isModalOpen && ( +
+ {/* KR */} + + {modalController.isKrOpen && ( +
+ + {krFetching ? ( + + ) : KeyResultData?.length === 0 ? ( +

Nenhum Resultado-chave Encontrado

+ ) : ( + KeyResultData?.map((kr) => ( + + )) + )} +
+ )} + + {/* CYCLE */} + + {modalController.isCycleOpen && ( +
+

Ciclo Anual

+
+ {cycleYears && + Object.keys(cycleYears).map((cycle) => ( + + ))} +
+ {filterData.cycle?.year && ( + <> + +

Trimestre

+
+ {cycleYears?.[filterData?.cycle?.year].map((cycle) => ( + + ))} +
+ + )} +
+ )} + + + {modalController.isDoneOpen && ( +
+ + + + +
+ )} +
+ )} +
+ ) +} diff --git a/src/components/Page/Team/Tabs/BoardFilters/messages.ts b/src/components/Page/Team/Tabs/BoardFilters/messages.ts new file mode 100644 index 000000000..f31b2b799 --- /dev/null +++ b/src/components/Page/Team/Tabs/BoardFilters/messages.ts @@ -0,0 +1,24 @@ +import { defineMessages } from 'react-intl' + +type SelectMenuMessage = 'iconChevronDownDesc' | 'iconChevronUpDesc' | 'defaultPlaceholder' + +export default defineMessages({ + iconChevronDownDesc: { + defaultMessage: 'Uma seta para baixo. Ao clicar nela você abrirá o menu de seleção', + id: 'rH+dGv', + description: + 'This is the desc attribute of our chevron down icon. It is used by screen readers', + }, + + iconChevronUpDesc: { + defaultMessage: 'Uma seta para cima. Ao clicar nela você fechará o menu de seleção', + id: 'ND5T6U', + description: 'This is the desc attribute of our chevron up icon. It is used by screen readers', + }, + + defaultPlaceholder: { + defaultMessage: 'Filtros', + id: 'IldkUk', + description: 'This is the default placeholder while selecting a given value in a select menu', + }, +}) diff --git a/src/components/Page/Team/Tabs/content/board-tab-content.tsx b/src/components/Page/Team/Tabs/content/board-tab-content.tsx index 709c11b99..87f74d6b0 100644 --- a/src/components/Page/Team/Tabs/content/board-tab-content.tsx +++ b/src/components/Page/Team/Tabs/content/board-tab-content.tsx @@ -1,12 +1,10 @@ -import { Box, HStack, MenuItemOption, Stack, Text } from '@chakra-ui/react' +import { Box, HStack, Stack, Text } from '@chakra-ui/react' import { useRouter } from 'next/router' import React, { useEffect, useState } from 'react' import { useIntl } from 'react-intl' import { useRecoilValue, useSetRecoilState } from 'recoil' -import { SelectMenu } from 'src/components/Base' import { SearchBar } from 'src/components/Base/SearchBar/wrapper' -import { useTeamKRData } from 'src/components/KeyResult/hooks/use-get-team-key-result' import BoardWrapper from 'src/components/TaskManagement/Board/wrapper' import { TaskInsertDrawer } from 'src/components/TaskManagement/InsertDrawer/wrapper' import { TaskDrawer } from 'src/components/TaskManagement/TaskDrawer' @@ -14,6 +12,8 @@ import { Team } from 'src/components/Team/types' import { teamAtomFamily } from 'src/state/recoil/team' import { selectedTeamIdHighlight } from 'src/state/recoil/team/highlight/selected-team-id-highlight' +import { BoardFilters } from '../BoardFilters' + import messages from './messages' interface BoardTabContentProperties { @@ -21,40 +21,40 @@ interface BoardTabContentProperties { } const TasksTabContent = ({ teamId }: BoardTabContentProperties) => { - const router = useRouter() - const setSelectedTeamId = useSetRecoilState(selectedTeamIdHighlight) + const defaultCycle = { + year: new Date().getFullYear().toString(), + quarter: Math.ceil((new Date().getMonth() + 1) / 3).toString(), + } const team = useRecoilValue(teamAtomFamily(teamId)) const [searchTaskInput, setSearchTaskInput] = useState() - const { data: KeyResultData, isFetching: krFetching } = useTeamKRData(teamId, '0') + const [resetFilters, setResetFilters] = useState(false) const intl = useIntl() + const router = useRouter() + + useEffect(() => { + if ( + router.query.key_result_id__id || + router.query.cy || + router.query.cy !== `${defaultCycle.year}+${defaultCycle.quarter}` || + router.query.show_done + ) { + setResetFilters(true) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [router.query]) useEffect(() => { setSelectedTeamId(teamId) }, [setSelectedTeamId, teamId]) - const handleQuery = (key: string) => (newValue: string | string[]) => { - if (newValue !== 'none') { - router.query[key] = newValue - router.push(router) - return true - } - - router.query[key] = undefined + const onResetFilters = () => { + router.query.key_result_id__id = undefined + router.query.show_done = undefined + router.query.cy = `${defaultCycle.year}+${defaultCycle.quarter}` router.push(router) - return true - } - - const krSelected = (): string | undefined => { - const key = router.query.kr ? router.query.kr : undefined - if (key) { - const selectedKr = KeyResultData?.find((kr) => kr.id === key) - return selectedKr ? selectedKr.title : undefined - } - - return key } return ( @@ -64,25 +64,18 @@ const TasksTabContent = ({ teamId }: BoardTabContentProperties) => { {intl.formatMessage(messages.boardTabHeaderTitle, { team: team?.name })} - - Selecionar - {KeyResultData?.map((keyResult) => ( - - {keyResult.title} - - ))} - + {resetFilters && ( + onResetFilters()} + > + Limpar filtros + + )} + { - const { mutate: archiveMutate } = useArchiveColumn(boardDomain, teamId) - const { mutate: deleteMutate } = useDeleteColumn(boardDomain, teamId) - - const [isDialogOpen, setDialogOpen] = useState(false) - - const archiveSubmit = useCallback(() => { - archiveMutate({ ids }) - }, [archiveMutate, ids]) - - const deleteSubmit = useCallback(() => { - deleteMutate({ ids }) - }, [deleteMutate, ids]) - - return ( - - setDialogOpen(false)} - /> - - - - - Arquivar todas as tarefas - setDialogOpen(true)}> - Excluir todas as tarefas - - - - ) -} - -export default ArchiveAndDeleteMenu diff --git a/src/components/TaskManagement/Board/components/auto-resize-text-area.tsx b/src/components/TaskManagement/Board/components/auto-resize-text-area.tsx deleted file mode 100644 index 20e412d5e..000000000 --- a/src/components/TaskManagement/Board/components/auto-resize-text-area.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { Textarea, TextareaProps } from '@chakra-ui/react' -import React from 'react' -import ResizeTextarea from 'react-textarea-autosize' - -const AutoResizeTextarea = React.forwardRef( - (properties, reference) => { - return