Skip to content

Commit

Permalink
Merge branch 'fix/issues-layout-mobx' into chore/issue-properties-mobx
Browse files Browse the repository at this point in the history
  • Loading branch information
gurusainath authored Oct 4, 2023
2 parents 0925122 + 7be038a commit 5433d7f
Show file tree
Hide file tree
Showing 16 changed files with 279 additions and 325 deletions.
2 changes: 1 addition & 1 deletion web/components/core/views/all-views.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion web/components/issues/issue-layouts/calendar/calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
<CalendarWeekHeader />
<div className="h-full w-full overflow-y-auto">
{calendarLayout === "month" ? (
<div className="h-full w-full grid grid-cols-1">
<div className="h-full w-full grid grid-cols-1 divide-y-[0.5px] divide-custom-border-200">
{allWeeksOfActiveMonth &&
Object.values(allWeeksOfActiveMonth).map((week: ICalendarWeek, weekIndex) => (
<CalendarWeekDays key={weekIndex} week={week} issues={issues} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -46,73 +47,63 @@ export const CalendarMonthsDropdown: React.FC = observer(() => {

return (
<Popover className="relative">
{({ close }) => (
<>
<Popover.Button className="outline-none text-xl font-semibold" disabled={calendarLayout === "week"}>
{calendarLayout === "month"
? `${MONTHS_LIST[activeMonthDate.getMonth() + 1].title} ${activeMonthDate.getFullYear()}`
: getWeekLayoutHeader()}
</Popover.Button>
<Transition
as={React.Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel>
<div className="absolute left-0 z-10 mt-1 bg-custom-background-100 border border-custom-border-200 shadow-custom-shadow-rg rounded w-56 p-3 divide-y divide-custom-border-200">
<div className="flex items-center justify-between gap-2 pb-3">
<button
type="button"
className="grid place-items-center"
onClick={() => {
const previousYear = new Date(activeMonthDate.getFullYear() - 1, activeMonthDate.getMonth(), 1);
handleDateChange(previousYear);

close();
}}
>
<ChevronLeft size={14} />
</button>
<span className="text-xs">{activeMonthDate.getFullYear()}</span>
<button
type="button"
className="grid place-items-center"
onClick={() => {
const nextYear = new Date(activeMonthDate.getFullYear() + 1, activeMonthDate.getMonth(), 1);
handleDateChange(nextYear);

close();
}}
>
<ChevronRight size={14} />
</button>
</div>
<div className="grid grid-cols-4 gap-4 items-stretch justify-items-stretch pt-3">
{Object.values(MONTHS_LIST).map((month, index) => (
<button
key={month.shortTitle}
type="button"
className="text-xs hover:bg-custom-background-80 rounded py-0.5"
onClick={() => {
const newDate = new Date(activeMonthDate.getFullYear(), index, 1);
handleDateChange(newDate);

close();
}}
>
{month.shortTitle}
</button>
))}
</div>
</div>
</Popover.Panel>
</Transition>
</>
)}
<Popover.Button className="outline-none text-xl font-semibold" disabled={calendarLayout === "week"}>
{calendarLayout === "month"
? `${MONTHS_LIST[activeMonthDate.getMonth() + 1].title} ${activeMonthDate.getFullYear()}`
: getWeekLayoutHeader()}
</Popover.Button>
<Transition
as={React.Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel>
<div className="absolute left-0 z-10 mt-1 bg-custom-background-100 border border-custom-border-200 shadow-custom-shadow-rg rounded w-56 p-3 divide-y divide-custom-border-200">
<div className="flex items-center justify-between gap-2 pb-3">
<button
type="button"
className="grid place-items-center"
onClick={() => {
const previousYear = new Date(activeMonthDate.getFullYear() - 1, activeMonthDate.getMonth(), 1);
handleDateChange(previousYear);
}}
>
<ChevronLeft size={14} />
</button>
<span className="text-xs">{activeMonthDate.getFullYear()}</span>
<button
type="button"
className="grid place-items-center"
onClick={() => {
const nextYear = new Date(activeMonthDate.getFullYear() + 1, activeMonthDate.getMonth(), 1);
handleDateChange(nextYear);
}}
>
<ChevronRight size={14} />
</button>
</div>
<div className="grid grid-cols-4 gap-4 items-stretch justify-items-stretch pt-3">
{Object.values(MONTHS_LIST).map((month, index) => (
<button
key={month.shortTitle}
type="button"
className="text-xs hover:bg-custom-background-80 rounded py-0.5"
onClick={() => {
const newDate = new Date(activeMonthDate.getFullYear(), index, 1);
handleDateChange(newDate);
}}
>
{month.shortTitle}
</button>
))}
</div>
</div>
</Popover.Panel>
</Transition>
</Popover>
);
});
2 changes: 1 addition & 1 deletion web/components/issues/issue-layouts/calendar/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export const CalendarHeader: React.FC = observer(() => {
<div className="flex items-center gap-1.5">
<button
type="button"
className="px-2.5 py-1 text-xs bg-custom-background-80 rounded font-medium"
className="px-2.5 py-1 text-xs bg-custom-background-80 rounded font-medium text-custom-text-200 hover:text-custom-text-100"
onClick={handleToday}
>
Today
Expand Down
6 changes: 3 additions & 3 deletions web/components/issues/issue-layouts/calendar/week-days.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ export const CalendarWeekDays: React.FC<Props> = observer((props) => {

return (
<div
className={`grid divide-x-[0.5px] divide-y-[0.5px] divide-custom-border-200 ${
showWeekends ? "grid-cols-7" : "grid-cols-5"
} ${calendarLayout === "month" ? "" : "h-full"}`}
className={`grid divide-x-[0.5px] divide-custom-border-200 ${showWeekends ? "grid-cols-7" : "grid-cols-5"} ${
calendarLayout === "month" ? "" : "h-full"
}`}
>
{Object.values(week).map((date: ICalendarDate) => {
if (!showWeekends && (date.date.getDay() === 0 || date.date.getDay() === 6)) return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";

// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import {
AppliedDateFilters,
Expand All @@ -17,65 +14,19 @@ import { X } from "lucide-react";
// helpers
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
// types
import { IIssueFilterOptions } from "types";
import { IIssueFilterOptions, IIssueLabels, IStateResponse, IUserLite } from "types";

export const AppliedFiltersList: React.FC = observer(() => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
type Props = {
appliedFilters: IIssueFilterOptions;
handleClearAllFilters: () => void;
handleRemoveFilter: (key: keyof IIssueFilterOptions, value: string | null) => void;
labels: IIssueLabels[] | undefined;
members: IUserLite[] | undefined;
states: IStateResponse | undefined;
};

const { issueFilter: issueFilterStore, project: projectStore } = useMobxStore();

const userFilters = issueFilterStore.userFilters;

// filters whose value not null or empty array
const appliedFilters: IIssueFilterOptions = {};
Object.entries(userFilters).forEach(([key, value]) => {
if (!value) return;

if (Array.isArray(value) && value.length === 0) return;

appliedFilters[key as keyof IIssueFilterOptions] = value;
});

const handleRemoveFilter = (key: keyof IIssueFilterOptions, value: string | null) => {
if (!workspaceSlug || !projectId) return;

// remove all values of the key if value is null
if (!value) {
issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
filters: {
[key]: null,
},
});
return;
}

// remove the passed value from the key
let newValues = issueFilterStore.userFilters?.[key] ?? [];
newValues = newValues.filter((val) => val !== value);

issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
filters: {
[key]: newValues,
},
});
};

const handleClearAllFilters = () => {
if (!workspaceSlug || !projectId) return;

const newFilters: IIssueFilterOptions = {};
Object.keys(userFilters).forEach((key) => {
newFilters[key as keyof IIssueFilterOptions] = null;
});

issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
filters: { ...newFilters },
});
};

// return if no filters are applied
if (Object.keys(appliedFilters).length === 0) return null;
export const AppliedFiltersList: React.FC<Props> = observer((props) => {
const { appliedFilters, handleClearAllFilters, handleRemoveFilter, labels, members, states } = props;

return (
<div className="flex items-stretch gap-2 flex-wrap bg-custom-background-100 p-4">
Expand All @@ -91,7 +42,7 @@ export const AppliedFiltersList: React.FC = observer(() => {
{(filterKey === "assignees" || filterKey === "created_by" || filterKey === "subscriber") && (
<AppliedMembersFilters
handleRemove={(val) => handleRemoveFilter(filterKey, val)}
members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)}
members={members}
values={value}
/>
)}
Expand All @@ -101,7 +52,7 @@ export const AppliedFiltersList: React.FC = observer(() => {
{filterKey === "labels" && (
<AppliedLabelsFilters
handleRemove={(val) => handleRemoveFilter("labels", val)}
labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? []}
labels={labels}
values={value}
/>
)}
Expand All @@ -111,7 +62,7 @@ export const AppliedFiltersList: React.FC = observer(() => {
{filterKey === "state" && (
<AppliedStateFilters
handleRemove={(val) => handleRemoveFilter("state", val)}
states={projectStore.states?.[projectId?.toString() ?? ""]}
states={states}
values={value}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export * from "./filters-list";
export * from "./label";
export * from "./members";
export * from "./priority";
export * from "./root";
export * from "./state";
export * from "./state-group";
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";

// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { AppliedFiltersList } from "components/issues";
// types
import { IIssueFilterOptions } from "types";

export const AppliedFiltersRoot: React.FC = observer(() => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;

const { issueFilter: issueFilterStore, project: projectStore } = useMobxStore();

const userFilters = issueFilterStore.userFilters;

// filters whose value not null or empty array
const appliedFilters: IIssueFilterOptions = {};
Object.entries(userFilters).forEach(([key, value]) => {
if (!value) return;

if (Array.isArray(value) && value.length === 0) return;

appliedFilters[key as keyof IIssueFilterOptions] = value;
});

const handleRemoveFilter = (key: keyof IIssueFilterOptions, value: string | null) => {
if (!workspaceSlug || !projectId) return;

// remove all values of the key if value is null
if (!value) {
issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
filters: {
[key]: null,
},
});
return;
}

// remove the passed value from the key
let newValues = issueFilterStore.userFilters?.[key] ?? [];
newValues = newValues.filter((val) => val !== value);

issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
filters: {
[key]: newValues,
},
});
};

const handleClearAllFilters = () => {
if (!workspaceSlug || !projectId) return;

const newFilters: IIssueFilterOptions = {};
Object.keys(userFilters).forEach((key) => {
newFilters[key as keyof IIssueFilterOptions] = null;
});

issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
filters: { ...newFilters },
});
};

// return if no filters are applied
if (Object.keys(appliedFilters).length === 0) return null;

return (
<AppliedFiltersList
appliedFilters={appliedFilters}
handleClearAllFilters={handleClearAllFilters}
handleRemoveFilter={handleRemoveFilter}
labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? []}
members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)}
states={projectStore.states?.[projectId?.toString() ?? ""]}
/>
);
});
Loading

0 comments on commit 5433d7f

Please # to comment.