From 5d5cdd6eca96f2501ecf1fe221f0a77adea320c1 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Mon, 2 Oct 2023 17:39:15 +0530 Subject: [PATCH 1/4] fix: calendar layout dividers --- web/components/issues/issue-layouts/calendar/calendar.tsx | 2 +- web/components/issues/issue-layouts/calendar/week-days.tsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/components/issues/issue-layouts/calendar/calendar.tsx b/web/components/issues/issue-layouts/calendar/calendar.tsx index b4d9aa4b2cd..507732e983f 100644 --- a/web/components/issues/issue-layouts/calendar/calendar.tsx +++ b/web/components/issues/issue-layouts/calendar/calendar.tsx @@ -38,7 +38,7 @@ export const CalendarChart: React.FC = observer((props) => {
{calendarLayout === "month" ? ( -
+
{allWeeksOfActiveMonth && Object.values(allWeeksOfActiveMonth).map((week: ICalendarWeek, weekIndex) => ( diff --git a/web/components/issues/issue-layouts/calendar/week-days.tsx b/web/components/issues/issue-layouts/calendar/week-days.tsx index 9041ee91b35..f6317b3a5eb 100644 --- a/web/components/issues/issue-layouts/calendar/week-days.tsx +++ b/web/components/issues/issue-layouts/calendar/week-days.tsx @@ -27,9 +27,9 @@ export const CalendarWeekDays: React.FC = observer((props) => { return (
{Object.values(week).map((date: ICalendarDate) => { if (!showWeekends && (date.date.getDay() === 0 || date.date.getDay() === 6)) return null; From f12f302be1e900acacc50d962894b5ecea4978d0 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Mon, 2 Oct 2023 18:22:56 +0530 Subject: [PATCH 2/4] refactor: filter selection components --- .../filters/header/filters/assignee.tsx | 30 +++---- .../filters/header/filters/created-by.tsx | 30 +++---- .../header/filters/filters-selection.tsx | 81 ++++++++++--------- .../filters/header/filters/labels.tsx | 20 ++--- .../filters/header/filters/state-group.tsx | 12 +-- .../filters/header/filters/state.tsx | 21 +++-- 6 files changed, 93 insertions(+), 101 deletions(-) diff --git a/web/components/issues/issue-layouts/filters/header/filters/assignee.tsx b/web/components/issues/issue-layouts/filters/header/filters/assignee.tsx index 252890d52e2..9e41784f8ca 100644 --- a/web/components/issues/issue-layouts/filters/header/filters/assignee.tsx +++ b/web/components/issues/issue-layouts/filters/header/filters/assignee.tsx @@ -1,34 +1,30 @@ import React, { useState } from "react"; -import { observer } from "mobx-react-lite"; -// mobx store -import { useMobxStore } from "lib/mobx/store-provider"; // components import { FilterHeader, FilterOption } from "components/issues"; // ui import { Avatar, Loader } from "components/ui"; +// types +import { IUserLite } from "types"; type Props = { appliedFilters: string[] | null; handleUpdate: (val: string) => void; itemsToRender: number; - projectId: string; + members: IUserLite[] | undefined; searchQuery: string; viewButtons: React.ReactNode; }; -export const FilterAssignees: React.FC = observer((props) => { - const { appliedFilters, handleUpdate, itemsToRender, projectId, searchQuery, viewButtons } = props; +export const FilterAssignees: React.FC = (props) => { + const { appliedFilters, handleUpdate, itemsToRender, members, searchQuery, viewButtons } = props; const [previewEnabled, setPreviewEnabled] = useState(true); - const store = useMobxStore(); - const { project: projectStore } = store; - const appliedFiltersCount = appliedFilters?.length ?? 0; - const filteredOptions = projectStore.members?.[projectId?.toString() ?? ""]?.filter((member) => - member.member.display_name.toLowerCase().includes(searchQuery.toLowerCase()) + const filteredOptions = members?.filter((member) => + member.display_name.toLowerCase().includes(searchQuery.toLowerCase()) ); return ( @@ -45,11 +41,11 @@ export const FilterAssignees: React.FC = observer((props) => { <> {filteredOptions.slice(0, itemsToRender).map((member) => ( handleUpdate(member.member?.id)} - icon={} - title={member.member?.display_name} + key={`assignees-${member.id}`} + isChecked={appliedFilters?.includes(member.id) ? true : false} + onClick={() => handleUpdate(member.id)} + icon={} + title={member.display_name} /> ))} {viewButtons} @@ -68,4 +64,4 @@ export const FilterAssignees: React.FC = observer((props) => { )} ); -}); +}; diff --git a/web/components/issues/issue-layouts/filters/header/filters/created-by.tsx b/web/components/issues/issue-layouts/filters/header/filters/created-by.tsx index 791e1e9319e..9be5bd05c1d 100644 --- a/web/components/issues/issue-layouts/filters/header/filters/created-by.tsx +++ b/web/components/issues/issue-layouts/filters/header/filters/created-by.tsx @@ -1,34 +1,30 @@ import React, { useState } from "react"; -import { observer } from "mobx-react-lite"; -// mobx store -import { useMobxStore } from "lib/mobx/store-provider"; // components import { FilterHeader, FilterOption } from "components/issues"; // ui import { Avatar, Loader } from "components/ui"; +// types +import { IUserLite } from "types"; type Props = { appliedFilters: string[] | null; handleUpdate: (val: string) => void; itemsToRender: number; - projectId: string; + members: IUserLite[] | undefined; searchQuery: string; viewButtons: React.ReactNode; }; -export const FilterCreatedBy: React.FC = observer((props) => { - const { appliedFilters, handleUpdate, itemsToRender, projectId, searchQuery, viewButtons } = props; +export const FilterCreatedBy: React.FC = (props) => { + const { appliedFilters, handleUpdate, itemsToRender, members, searchQuery, viewButtons } = props; const [previewEnabled, setPreviewEnabled] = useState(true); - const store = useMobxStore(); - const { project: projectStore } = store; - const appliedFiltersCount = appliedFilters?.length ?? 0; - const filteredOptions = projectStore.members?.[projectId?.toString() ?? ""]?.filter((member) => - member.member.display_name.toLowerCase().includes(searchQuery.toLowerCase()) + const filteredOptions = members?.filter((member) => + member.display_name.toLowerCase().includes(searchQuery.toLowerCase()) ); return ( @@ -45,11 +41,11 @@ export const FilterCreatedBy: React.FC = observer((props) => { <> {filteredOptions.slice(0, itemsToRender).map((member) => ( handleUpdate(member.member?.id)} - icon={} - title={member.member?.display_name} + key={`created-by-${member.id}`} + isChecked={appliedFilters?.includes(member.id) ? true : false} + onClick={() => handleUpdate(member.id)} + icon={} + title={member.display_name} /> ))} {viewButtons} @@ -68,4 +64,4 @@ export const FilterCreatedBy: React.FC = observer((props) => { )} ); -}); +}; diff --git a/web/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx b/web/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx index 2e31a16a227..8fe0fe9932b 100644 --- a/web/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx +++ b/web/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx @@ -189,25 +189,27 @@ export const FilterSelection: React.FC = observer((props) => { handleUpdate={(val) => handleFiltersUpdate("state_group", val)} itemsToRender={filtersToRender.state_group?.currentLength ?? 0} searchQuery={filtersSearchQuery} + viewButtons={ +
+ {isViewMoreVisible("state_group") && ( + + )} + {isViewLessVisible("state_group") && ( + + )} +
+ } /> -
- {isViewMoreVisible("state_group") && ( - - )} - {isViewLessVisible("state_group") && ( - - )} -
)} @@ -219,23 +221,28 @@ export const FilterSelection: React.FC = observer((props) => { handleUpdate={(val) => handleFiltersUpdate("state", val)} itemsToRender={filtersToRender.state?.currentLength ?? 0} searchQuery={filtersSearchQuery} - projectId={projectId} + states={projectStore.states?.[projectId]} + viewButtons={ +
+ {isViewMoreVisible("state") && ( + + )} + {isViewLessVisible("state") && ( + + )} +
+ } /> -
- {isViewMoreVisible("state") && ( - - )} - {isViewLessVisible("state") && ( - - )} -
)} @@ -246,7 +253,7 @@ export const FilterSelection: React.FC = observer((props) => { appliedFilters={filters.assignees ?? null} handleUpdate={(val) => handleFiltersUpdate("assignees", val)} itemsToRender={filtersToRender.assignees?.currentLength ?? 0} - projectId={projectId} + members={projectStore.members?.[projectId]?.map((m) => m.member) ?? undefined} searchQuery={filtersSearchQuery} viewButtons={
@@ -279,7 +286,7 @@ export const FilterSelection: React.FC = observer((props) => { appliedFilters={filters.created_by ?? null} handleUpdate={(val) => handleFiltersUpdate("created_by", val)} itemsToRender={filtersToRender.created_by?.currentLength ?? 0} - projectId={projectId} + members={projectStore.members?.[projectId]?.map((m) => m.member) ?? undefined} searchQuery={filtersSearchQuery} viewButtons={
@@ -312,7 +319,7 @@ export const FilterSelection: React.FC = observer((props) => { appliedFilters={filters.labels ?? null} handleUpdate={(val) => handleFiltersUpdate("labels", val)} itemsToRender={filtersToRender.labels?.currentLength ?? 0} - projectId={projectId} + labels={projectStore.labels?.[projectId] ?? undefined} searchQuery={filtersSearchQuery} viewButtons={
diff --git a/web/components/issues/issue-layouts/filters/header/filters/labels.tsx b/web/components/issues/issue-layouts/filters/header/filters/labels.tsx index 407bd707fe4..a4140507633 100644 --- a/web/components/issues/issue-layouts/filters/header/filters/labels.tsx +++ b/web/components/issues/issue-layouts/filters/header/filters/labels.tsx @@ -1,12 +1,11 @@ import React, { useState } from "react"; -import { observer } from "mobx-react-lite"; -// mobx store -import { useMobxStore } from "lib/mobx/store-provider"; // components import { FilterHeader, FilterOption } from "components/issues"; // ui import { Loader } from "components/ui"; +// types +import { IIssueLabels } from "types"; const LabelIcons = ({ color }: { color: string }) => ( @@ -16,24 +15,19 @@ type Props = { appliedFilters: string[] | null; handleUpdate: (val: string) => void; itemsToRender: number; - projectId: string; + labels: IIssueLabels[] | undefined; searchQuery: string; viewButtons: React.ReactNode; }; -export const FilterLabels: React.FC = observer((props) => { - const { appliedFilters, handleUpdate, itemsToRender, projectId, searchQuery, viewButtons } = props; +export const FilterLabels: React.FC = (props) => { + const { appliedFilters, handleUpdate, itemsToRender, labels, searchQuery, viewButtons } = props; const [previewEnabled, setPreviewEnabled] = useState(true); - const store = useMobxStore(); - const { project: projectStore } = store; - const appliedFiltersCount = appliedFilters?.length ?? 0; - const filteredOptions = projectStore.labels?.[projectId?.toString() ?? ""]?.filter((label) => - label.name.toLowerCase().includes(searchQuery.toLowerCase()) - ); + const filteredOptions = labels?.filter((label) => label.name.toLowerCase().includes(searchQuery.toLowerCase())); return ( <> @@ -72,4 +66,4 @@ export const FilterLabels: React.FC = observer((props) => { )} ); -}); +}; diff --git a/web/components/issues/issue-layouts/filters/header/filters/state-group.tsx b/web/components/issues/issue-layouts/filters/header/filters/state-group.tsx index fd22cd10d26..c5551a30dd3 100644 --- a/web/components/issues/issue-layouts/filters/header/filters/state-group.tsx +++ b/web/components/issues/issue-layouts/filters/header/filters/state-group.tsx @@ -13,10 +13,11 @@ type Props = { handleUpdate: (val: string) => void; itemsToRender: number; searchQuery: string; + viewButtons: React.ReactNode; }; export const FilterStateGroup: React.FC = observer((props) => { - const { appliedFilters, handleUpdate, itemsToRender, searchQuery } = props; + const { appliedFilters, handleUpdate, itemsToRender, searchQuery, viewButtons } = props; const [previewEnabled, setPreviewEnabled] = useState(true); @@ -34,9 +35,8 @@ export const FilterStateGroup: React.FC = observer((props) => { {previewEnabled && (
{filteredOptions.length > 0 ? ( - filteredOptions - .slice(0, itemsToRender) - .map((stateGroup) => ( + <> + {filteredOptions.slice(0, itemsToRender).map((stateGroup) => ( = observer((props) => { icon={} title={stateGroup.title} /> - )) + ))} + {viewButtons} + ) : (

No matches found

)} diff --git a/web/components/issues/issue-layouts/filters/header/filters/state.tsx b/web/components/issues/issue-layouts/filters/header/filters/state.tsx index 6a1232588d1..ae719758af9 100644 --- a/web/components/issues/issue-layouts/filters/header/filters/state.tsx +++ b/web/components/issues/issue-layouts/filters/header/filters/state.tsx @@ -1,8 +1,5 @@ import React, { useState } from "react"; -import { observer } from "mobx-react-lite"; -// mobx store -import { useMobxStore } from "lib/mobx/store-provider"; // components import { FilterHeader, FilterOption } from "components/issues"; // ui @@ -11,25 +8,24 @@ import { Loader } from "components/ui"; import { StateGroupIcon } from "components/icons"; // helpers import { getStatesList } from "helpers/state.helper"; +// types +import { IStateResponse } from "types"; type Props = { appliedFilters: string[] | null; handleUpdate: (val: string) => void; itemsToRender: number; - projectId: string; searchQuery: string; + states: IStateResponse | undefined; + viewButtons: React.ReactNode; }; -export const FilterState: React.FC = observer((props) => { - const { appliedFilters, handleUpdate, itemsToRender, projectId, searchQuery } = props; +export const FilterState: React.FC = (props) => { + const { appliedFilters, handleUpdate, itemsToRender, searchQuery, states, viewButtons } = props; const [previewEnabled, setPreviewEnabled] = useState(true); - const store = useMobxStore(); - const { project: projectStore } = store; - - const statesByGroups = projectStore.states?.[projectId?.toString() ?? ""]; - const statesList = getStatesList(statesByGroups); + const statesList = getStatesList(states); const appliedFiltersCount = appliedFilters?.length ?? 0; @@ -56,6 +52,7 @@ export const FilterState: React.FC = observer((props) => { title={state.name} /> ))} + {viewButtons} ) : (

No matches found

@@ -71,4 +68,4 @@ export const FilterState: React.FC = observer((props) => { )} ); -}); +}; From c99a5d3f063245797478c4190719d89483ad261e Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Tue, 3 Oct 2023 00:14:01 +0530 Subject: [PATCH 3/4] fix: dropdown closing after selection --- .../calendar/dropdowns/months-dropdown.tsx | 127 ++++++++---------- 1 file changed, 59 insertions(+), 68 deletions(-) diff --git a/web/components/issues/issue-layouts/calendar/dropdowns/months-dropdown.tsx b/web/components/issues/issue-layouts/calendar/dropdowns/months-dropdown.tsx index 2b6c43b255c..4bb5ebcf0fb 100644 --- a/web/components/issues/issue-layouts/calendar/dropdowns/months-dropdown.tsx +++ b/web/components/issues/issue-layouts/calendar/dropdowns/months-dropdown.tsx @@ -4,9 +4,10 @@ import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; +// icons +import { ChevronLeft, ChevronRight } from "lucide-react"; // constants import { MONTHS_LIST } from "constants/calendar"; -import { ChevronLeft, ChevronRight } from "lucide-react"; export const CalendarMonthsDropdown: React.FC = observer(() => { const { calendar: calendarStore, issueFilter: issueFilterStore } = useMobxStore(); @@ -46,73 +47,63 @@ export const CalendarMonthsDropdown: React.FC = observer(() => { return ( - {({ close }) => ( - <> - - {calendarLayout === "month" - ? `${MONTHS_LIST[activeMonthDate.getMonth() + 1].title} ${activeMonthDate.getFullYear()}` - : getWeekLayoutHeader()} - - - -
-
- - {activeMonthDate.getFullYear()} - -
-
- {Object.values(MONTHS_LIST).map((month, index) => ( - - ))} -
-
-
-
- - )} + + {calendarLayout === "month" + ? `${MONTHS_LIST[activeMonthDate.getMonth() + 1].title} ${activeMonthDate.getFullYear()}` + : getWeekLayoutHeader()} + + + +
+
+ + {activeMonthDate.getFullYear()} + +
+
+ {Object.values(MONTHS_LIST).map((month, index) => ( + + ))} +
+
+
+
); }); From 16b0369537bcba269efafc37c7917d6fe830f82a Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Wed, 4 Oct 2023 11:56:15 +0530 Subject: [PATCH 4/4] refactor: filters components --- web/components/core/views/all-views.tsx | 4 +- .../issues/issue-layouts/calendar/header.tsx | 2 +- .../filters/applied-filters/filters-list.tsx | 77 ++------ .../filters/applied-filters/index.ts | 1 + .../filters/applied-filters/root.tsx | 79 ++++++++ .../header/filters/filters-selection.tsx | 168 ++++++------------ .../filters/header/filters/start-date.tsx | 9 +- .../filters/header/filters/target-date.tsx | 9 +- 8 files changed, 160 insertions(+), 189 deletions(-) create mode 100644 web/components/issues/issue-layouts/filters/applied-filters/root.tsx diff --git a/web/components/core/views/all-views.tsx b/web/components/core/views/all-views.tsx index c5fcc7300c2..85830ee273a 100644 --- a/web/components/core/views/all-views.tsx +++ b/web/components/core/views/all-views.tsx @@ -6,7 +6,7 @@ import useSWR from "swr"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components -import { AppliedFiltersList, CalendarLayout, GanttLayout, KanBanLayout, SpreadsheetLayout } from "components/issues"; +import { AppliedFiltersRoot, CalendarLayout, GanttLayout, KanBanLayout, SpreadsheetLayout } from "components/issues"; export const AllViews: React.FC = observer(() => { const router = useRouter(); @@ -35,7 +35,7 @@ export const AllViews: React.FC = observer(() => { return (
- + {activeLayout === "kanban" ? ( ) : activeLayout === "calendar" ? ( diff --git a/web/components/issues/issue-layouts/calendar/header.tsx b/web/components/issues/issue-layouts/calendar/header.tsx index 363719920ca..034be98c4c6 100644 --- a/web/components/issues/issue-layouts/calendar/header.tsx +++ b/web/components/issues/issue-layouts/calendar/header.tsx @@ -86,7 +86,7 @@ export const CalendarHeader: React.FC = observer(() => {
+ )} + {isViewLessVisible && ( + + )} +
+); + export const FilterSelection: React.FC = observer((props) => { const { filters, handleFiltersUpdate, layoutDisplayFiltersOptions, projectId } = props; @@ -157,25 +180,12 @@ export const FilterSelection: React.FC = observer((props) => { itemsToRender={filtersToRender.priority?.currentLength ?? 0} searchQuery={filtersSearchQuery} viewButtons={ -
- {/* TODO: handle view more and less in a better way */} - {isViewMoreVisible("priority") && ( - - )} - {isViewLessVisible("priority") && ( - - )} -
+ handleViewLess("priority")} + handleMore={() => handleViewMore("priority")} + /> } />
@@ -190,24 +200,12 @@ export const FilterSelection: React.FC = observer((props) => { itemsToRender={filtersToRender.state_group?.currentLength ?? 0} searchQuery={filtersSearchQuery} viewButtons={ -
- {isViewMoreVisible("state_group") && ( - - )} - {isViewLessVisible("state_group") && ( - - )} -
+ handleViewLess("state_group")} + handleMore={() => handleViewMore("state_group")} + /> } />
@@ -223,24 +221,12 @@ export const FilterSelection: React.FC = observer((props) => { searchQuery={filtersSearchQuery} states={projectStore.states?.[projectId]} viewButtons={ -
- {isViewMoreVisible("state") && ( - - )} - {isViewLessVisible("state") && ( - - )} -
+ handleViewLess("state")} + handleMore={() => handleViewMore("state")} + /> } />
@@ -256,24 +242,12 @@ export const FilterSelection: React.FC = observer((props) => { members={projectStore.members?.[projectId]?.map((m) => m.member) ?? undefined} searchQuery={filtersSearchQuery} viewButtons={ -
- {isViewMoreVisible("assignees") && ( - - )} - {isViewLessVisible("assignees") && ( - - )} -
+ handleViewLess("assignees")} + handleMore={() => handleViewMore("assignees")} + /> } />
@@ -289,24 +263,12 @@ export const FilterSelection: React.FC = observer((props) => { members={projectStore.members?.[projectId]?.map((m) => m.member) ?? undefined} searchQuery={filtersSearchQuery} viewButtons={ -
- {isViewMoreVisible("created_by") && ( - - )} - {isViewLessVisible("created_by") && ( - - )} -
+ handleViewLess("created_by")} + handleMore={() => handleViewMore("created_by")} + /> } />
@@ -322,24 +284,12 @@ export const FilterSelection: React.FC = observer((props) => { labels={projectStore.labels?.[projectId] ?? undefined} searchQuery={filtersSearchQuery} viewButtons={ -
- {isViewMoreVisible("labels") && ( - - )} - {isViewLessVisible("labels") && ( - - )} -
+ handleViewLess("labels")} + handleMore={() => handleViewMore("labels")} + /> } />
diff --git a/web/components/issues/issue-layouts/filters/header/filters/start-date.tsx b/web/components/issues/issue-layouts/filters/header/filters/start-date.tsx index ad5ed955af8..e93f1fa7d4b 100644 --- a/web/components/issues/issue-layouts/filters/header/filters/start-date.tsx +++ b/web/components/issues/issue-layouts/filters/header/filters/start-date.tsx @@ -49,15 +49,10 @@ export const FilterStartDate: React.FC = observer((props) => { isChecked={appliedFilters?.includes(option.value) ? true : false} onClick={() => handleUpdate(option.value)} title={option.name} - multiple={false} + multiple /> ))} - setIsDateFilterModalOpen(true)} - title="Custom" - multiple={false} - /> + setIsDateFilterModalOpen(true)} title="Custom" multiple /> ) : (

No matches found

diff --git a/web/components/issues/issue-layouts/filters/header/filters/target-date.tsx b/web/components/issues/issue-layouts/filters/header/filters/target-date.tsx index c6ee45b04d3..c007aa039a1 100644 --- a/web/components/issues/issue-layouts/filters/header/filters/target-date.tsx +++ b/web/components/issues/issue-layouts/filters/header/filters/target-date.tsx @@ -49,15 +49,10 @@ export const FilterTargetDate: React.FC = observer((props) => { isChecked={appliedFilters?.includes(option.value) ? true : false} onClick={() => handleUpdate(option.value)} title={option.name} - multiple={false} + multiple /> ))} - setIsDateFilterModalOpen(true)} - title="Custom" - multiple={false} - /> + setIsDateFilterModalOpen(true)} title="Custom" multiple /> ) : (

No matches found