Skip to content

Commit

Permalink
3104-3105-3106-3107 feature/vertical sidebar, projects, favorites and…
Browse files Browse the repository at this point in the history
… role based navigation in sidebar (#3199)

* fix(web): [Vertical Sidenar] Fix fullwidth switch with vertical sidebar

* refactor(web): [Vertical Sidebar] retrieves projects data, get sidebar data based on user roles

* refactor(web): [Vertical Sidebar] fix alignments of project sidebar project

* refactor(web): [Vertical Sidebar] add sidebar traductions

* refactor(web): [Vertical Sidebar] make favorite tasks persistence

* refactor(web): [Vertical Sidebar] add favorite feature on card-menu-item

* refactor(web): [Favorite] add favorite feature on task detail

* fix(web): fix deepscan errors

* refactor(web): [Vertical Sidebar] Add TypeScript type definitions to MainSidebarTrigger and improve maintainability.

* refactor(web): [Types] Add TypeScript interfaces for role definitions and type safety to PERMISSION_ROLES mapping

* refactor(web): [Typo] Fix typo in sidebar translation key.

* refactor(web): [Favorite] Consider optimizing toggleFavorite implementation.

* refactor(web): [spelling] Fix grammatical error in favorites message.
  • Loading branch information
NdekoCode authored Oct 28, 2024
1 parent 486469e commit 347e93a
Show file tree
Hide file tree
Showing 35 changed files with 3,353 additions and 2,785 deletions.
33 changes: 16 additions & 17 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"caseSensitive": false,
"$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
"words": [
" X",
" X ",
"accepte",
"Accordian",
"adipiscing",
Expand Down Expand Up @@ -38,6 +40,7 @@
"asel",
"Authentificate",
"authjs",
"autorun",
"barcodes",
"billrate",
"binutils",
Expand Down Expand Up @@ -74,6 +77,7 @@
"Codacy",
"codecov",
"Codementor",
"collapsable",
"Combox",
"combx",
"commitlint",
Expand Down Expand Up @@ -114,6 +118,7 @@
"Efate",
"eiusmod",
"electronmon",
"Elipssis",
"elit",
"ellipsize",
"embla",
Expand All @@ -125,9 +130,12 @@
"Environtment",
"errr",
"everco",
"evereq",
"everteamsdesktop",
"everteamswebserver",
"excalidraw",
"exclamationcircleo",
"expanded",
"exposdk",
"extramenu",
"Fakaofo",
Expand All @@ -146,6 +154,7 @@
"Galery",
"gauzystage",
"gcloud",
"gitops",
"Gitter",
"GlobalSkeleton",
"gradlew",
Expand Down Expand Up @@ -226,6 +235,7 @@
"Loadtasks",
"localstorage",
"locatio",
"locutus",
"loglevel",
"longpress",
"Lorem",
Expand Down Expand Up @@ -253,6 +263,8 @@
"Northflank",
"Notif",
"nsis",
"nums",
"offcanvas",
"Opena",
"opentelemetry",
"Ordereds",
Expand Down Expand Up @@ -349,6 +361,7 @@
"tblr",
"teamsupercell",
"teamtask",
"TEAMTASKS",
"tempor",
"testid",
"timegrid",
Expand All @@ -364,6 +377,7 @@
"TRANSFERT",
"Transpiles",
"tsbuildinfo",
"twing",
"typeof",
"uicolors",
"uidotdev",
Expand Down Expand Up @@ -394,29 +408,14 @@
"worksace",
"Worspace",
"X",
"X ",
"xcodebuild",
"xcodeproj",
"xcworkspace",
"Xlarge",
"xlcard",
"xlight",
"yellowbox",
"twing",
"gitops",
"autorun",
"locutus",
"X",
"offcanvas",
"nums",
"Elipssis",
"evereq",
"everteamswebserver",
"expanded",
"expanded",
" X",
" X ",
"X ",
"collapsable"
"yellowbox"
],
"useGitignore": true,
"ignorePaths": [
Expand Down
7 changes: 5 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
"source.fixAll": "explicit",
"source.organizeImports": "never",
"source.sortMembers": "never",
"organizeImports": "never"
"organizeImports": "never",
"source.removeUnusedImports": "always"
},
"vsicons.presets.angular": true,
"deepscan.enable": true,
"cSpell.words": ["Timepicker"],
"cSpell.words": [
"Timepicker"
],
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true,
Expand Down
44 changes: 44 additions & 0 deletions apps/web/app/hooks/features/useActiveTeam.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use client';

import { useOrganizationTeams, useTimer } from '@app/hooks';
import { useToast } from '@components/ui/use-toast';
import { useCallback } from 'react';
import { TeamItem } from '@/lib/features/team/team-item';
import { useTranslations } from 'next-intl';

export const useActiveTeam = () => {
const { activeTeam, setActiveTeam } = useOrganizationTeams();
const { timerStatus, stopTimer } = useTimer();
const t = useTranslations();
const { toast } = useToast();
const onChangeActiveTeam = useCallback(
(item: TeamItem) => {
if (item.data) {
/**
* If timer started in Teams and user switches the Team, stop the timer
*/
if (
timerStatus &&
timerStatus?.running &&
timerStatus.lastLog &&
timerStatus.lastLog.organizationTeamId &&
timerStatus.lastLog.source === 'TEAMS' &&
activeTeam &&
activeTeam?.id &&
timerStatus.lastLog.organizationTeamId === activeTeam?.id
) {
toast({
variant: 'default',
title: t('timer.TEAM_SWITCH.STOPPED_TIMER_TOAST_TITLE'),
description: t('timer.TEAM_SWITCH.STOPPED_TIMER_TOAST_DESCRIPTION')
});
stopTimer();
}

setActiveTeam(item.data);
}
},
[setActiveTeam, timerStatus, stopTimer, activeTeam, toast, t]
);
return { activeTeam, setActiveTeam, onChangeActiveTeam };
};
47 changes: 47 additions & 0 deletions apps/web/app/hooks/features/useFavoritesTask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { useTeamTasks } from '@/app/hooks/features/useTeamTasks';
import { ITeamTask } from '@/app/interfaces/ITask';
import { useAtom } from 'jotai';
import { favoriteTasksStorageAtom } from '@/app/stores/team-tasks';
import { useCallback } from 'react';
/**
* A React hook that manages a list of favorite tasks for a team.
*
* The `useFavoritesTask` hook returns an object with the following properties:
*
* - `tasks`: The list of all tasks for the team, obtained from the `useTeamTasks` hook.
* - `favoriteTasks`: The list of favorite tasks.
* - `toggleFavorite`: A function that toggles the favorite status of a given task.
* - `isFavorite`: A function that checks if a given task is a favorite.
* - `addFavorite`: A function that adds a task to the list of favorites.
*/

export const useFavoritesTask = () => {
const { tasks } = useTeamTasks();
const [favoriteTasks, setFavoriteTasks] = useAtom(favoriteTasksStorageAtom);

const toggleFavorite = useCallback((task: ITeamTask) => {
if (!task?.id) {
console.warn('Invalid task provided to toggleFavorite');
return;
}
setFavoriteTasks((prev) =>
prev.some((t) => t.id === task.id) ? prev.filter((t) => t.id !== task.id) : [...prev, task]
);
}, []);

const isFavorite = useCallback((task: ITeamTask) => favoriteTasks.some((t) => t.id === task.id), [favoriteTasks]);

const addFavorite = useCallback((task: ITeamTask) => {
if (!isFavorite(task)) {
setFavoriteTasks((prev) => [...prev, task]);
}
}, []);

return {
tasks,
favoriteTasks,
toggleFavorite,
isFavorite,
addFavorite
};
};
107 changes: 59 additions & 48 deletions apps/web/app/hooks/features/useOrganizationTeamManagers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,67 @@ import { useAuthenticateUser } from './useAuthenticateUser';
import { useOrganizationTeams } from './useOrganizationTeams';
import { filterValue } from '@app/stores/all-teams';
import { useMemo } from 'react';

/**
* Provides a hook that returns the teams managed by the authenticated user, along with the ability to filter those teams based on the timer status of their members.
*
* @returns An object with two properties:
* - `userManagedTeams`: An array of teams that the authenticated user manages.
* - `filteredTeams`: An array of teams that the authenticated user manages, filtered based on the `filterValue` atom.
*/
export function useOrganizationAndTeamManagers() {
const { user } = useAuthenticateUser();
const { teams } = useOrganizationTeams();
const { value: filtered } = useAtomValue(filterValue);
const { user } = useAuthenticateUser();
const { teams } = useOrganizationTeams();
const { value: filtered } = useAtomValue(filterValue);

const userManagedTeams = useMemo(() => {
return teams.filter((team) =>
team.members.some(
(member) =>
member.employee?.user?.id === user?.id &&
member.role?.name === 'MANAGER'
)
);
}, [teams, user]);
/**
* Filters the teams managed by the authenticated user.
*
* @returns An array of teams that the authenticated user manages, where the authenticated user has the 'MANAGER' role for at least one member of the team.
*/
const userManagedTeams = useMemo(() => {
return teams.filter((team) =>
team.members.some((member) => member.employee?.user?.id === user?.id && member.role?.name === 'MANAGER')
);
}, [teams, user]);

const filteredTeams = useMemo(() => {
return filtered === 'all'
? userManagedTeams
: filtered === 'pause'
? userManagedTeams.map((team) => ({
...team,
members: team.members.filter(
(member) => member.timerStatus === 'pause'
)
}))
: filtered === 'running'
? userManagedTeams.map((team) => ({
...team,
members: team.members.filter(
(member) => member.timerStatus === 'running'
)
}))
: filtered === 'suspended'
? userManagedTeams.map((team) => ({
...team,
members: team.members.filter(
(member) => member.timerStatus === 'suspended'
)
}))
: filtered === 'invited'
? userManagedTeams.map((team) => ({
...team,
members: team.members.filter((member) => member.employee.acceptDate)
}))
: userManagedTeams;
}, [filtered, userManagedTeams]);
/**
* Filters the teams managed by the authenticated user based on the `filterValue` atom.
*
* @returns An array of teams that the authenticated user manages, filtered based on the `filterValue` atom. The filtering options include:
* - 'all': Returns all teams managed by the authenticated user.
* - 'pause': Returns teams where at least one member has a timer status of 'pause'.
* - 'running': Returns teams where at least one member has a timer status of 'running'.
* - 'suspended': Returns teams where at least one member has a timer status of 'suspended'.
* - 'invited': Returns teams where at least one member has an `acceptDate` value.
*/
const filteredTeams = useMemo(() => {
return filtered === 'all'
? userManagedTeams
: filtered === 'pause'
? userManagedTeams.map((team) => ({
...team,
members: team.members.filter((member) => member.timerStatus === 'pause')
}))
: filtered === 'running'
? userManagedTeams.map((team) => ({
...team,
members: team.members.filter((member) => member.timerStatus === 'running')
}))
: filtered === 'suspended'
? userManagedTeams.map((team) => ({
...team,
members: team.members.filter((member) => member.timerStatus === 'suspended')
}))
: filtered === 'invited'
? userManagedTeams.map((team) => ({
...team,
members: team.members.filter((member) => member.employee.acceptDate)
}))
: userManagedTeams;
}, [filtered, userManagedTeams]);

return {
userManagedTeams,
filteredTeams
};
return {
userManagedTeams,
filteredTeams
};
}
Loading

0 comments on commit 347e93a

Please sign in to comment.