Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Show | Edit project information in the task details page #3347

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion apps/web/app/api/organization-projects/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app';

import { editOrganizationProjectsRequest } from '@app/services/server/requests';
import { editOrganizationProjectsRequest, getOrganizationProjectRequest } from '@app/services/server/requests';
import { NextResponse } from 'next/server';

export async function PUT(req: Request, { params }: { params: { id: string } }) {
Expand All @@ -23,3 +23,22 @@ export async function PUT(req: Request, { params }: { params: { id: string } })

return $res(response.data);
}

export async function GET(req: Request, { params }: { params: { id: string } }) {
const res = new NextResponse();
if (!params.id) {
return;
}
CREDO23 marked this conversation as resolved.
Show resolved Hide resolved

const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res);

if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });

const response = await getOrganizationProjectRequest({
bearer_token: access_token,
id: params.id,
tenantId
});

return $res(response.data);
}
19 changes: 18 additions & 1 deletion apps/web/app/api/organization-projects/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app';

import { createOrganizationProjectRequest } from '@app/services/server/requests';
import { createOrganizationProjectRequest, getOrganizationProjectsRequest } from '@app/services/server/requests';
import { NextResponse } from 'next/server';

export async function POST(req: Request) {
Expand All @@ -19,3 +19,20 @@ export async function POST(req: Request) {

return $res(response.data);
}

export async function GET(req: Request) {
const res = new NextResponse();

const { $res, user, access_token, tenantId, organizationId } = await authenticatedGuard(req, res);
CREDO23 marked this conversation as resolved.
Show resolved Hide resolved

if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });


const response = await getOrganizationProjectsRequest({
bearer_token: access_token,
tenantId,
organizationId
});

return $res(response.data);
}
CREDO23 marked this conversation as resolved.
Show resolved Hide resolved
122 changes: 73 additions & 49 deletions apps/web/app/hooks/features/useOrganizationProjects.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,83 @@
import {
editOrganizationProjectSettingAPI,
editOrganizationProjectAPI
editOrganizationProjectAPI,
getOrganizationProjectAPI,
getOrganizationProjectsAPI
} from '@app/services/client/api';
import { userState } from '@app/stores';
import { useCallback } from 'react';
import { useAtom } from 'jotai';
import { useQuery } from '../useQuery';
import { organizationProjectsState } from '@/app/stores/organization-projects';

export function useOrganizationProjects() {
const [user] = useAtom(userState);

const {
loading: editOrganizationProjectLoading,
queryCall: editOrganizationProjectQueryCall
} = useQuery(editOrganizationProjectAPI);

const {
loading: editOrganizationProjectSettingLoading,
queryCall: editOrganizationProjectSettingQueryCall
} = useQuery(editOrganizationProjectSettingAPI);

const editOrganizationProjectSetting = useCallback(
(id: string, data: any) => {
if (user?.tenantId) {
return editOrganizationProjectSettingQueryCall(
id,
data,
user?.tenantId || ''
).then((res) => {
return res;
});
}
},
[user, editOrganizationProjectSettingQueryCall]
);

const editOrganizationProject = useCallback(
(id: string, data: any) => {
if (user?.tenantId) {
return editOrganizationProjectQueryCall(
id,
data,
user?.tenantId || ''
).then((res) => {
return res;
});
}
},
[user, editOrganizationProjectQueryCall]
);

return {
editOrganizationProjectSetting,
editOrganizationProjectSettingLoading,
editOrganizationProject,
editOrganizationProjectLoading
};
const [user] = useAtom(userState);
const [organizationProjects, setOrganizationProjects] = useAtom(organizationProjectsState);

const { loading: editOrganizationProjectLoading, queryCall: editOrganizationProjectQueryCall } =
useQuery(editOrganizationProjectAPI);

const { loading: editOrganizationProjectSettingLoading, queryCall: editOrganizationProjectSettingQueryCall } =
useQuery(editOrganizationProjectSettingAPI);

const { loading: getOrganizationProjectLoading, queryCall: getOrganizationProjectQueryCall } =
useQuery(getOrganizationProjectAPI);

const { loading: getOrganizationProjectsLoading, queryCall: getOrganizationProjectsQueryCall } =
useQuery(getOrganizationProjectsAPI);

const editOrganizationProjectSetting = useCallback(
(id: string, data: any) => {
if (user?.tenantId) {
return editOrganizationProjectSettingQueryCall(id, data, user?.tenantId || '').then((res) => {
return res;
});
}
},
[user, editOrganizationProjectSettingQueryCall]
);

const editOrganizationProject = useCallback(
(id: string, data: any) => {
if (user?.tenantId) {
return editOrganizationProjectQueryCall(id, data, user?.tenantId || '').then((res) => {
return res;
});
}
},
[user, editOrganizationProjectQueryCall]
);
CREDO23 marked this conversation as resolved.
Show resolved Hide resolved

const getOrganizationProject = useCallback(
async (id: string) => {
try {
return await getOrganizationProjectQueryCall(id);
} catch (error) {
console.log(error);
}
},
[getOrganizationProjectQueryCall]
);

const getOrganizationProjects = useCallback(async () => {
try {
const res = await getOrganizationProjectsQueryCall();

setOrganizationProjects(res.data.items);
} catch (error) {
console.log(error);
}
}, [getOrganizationProjectsQueryCall, setOrganizationProjects]);
Comment on lines +51 to +70
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Standardize the return strategy for get operations

The get operations have inconsistent return strategies:

  • getOrganizationProject returns the API response directly
  • getOrganizationProjects updates state but doesn't return anything

Consider standardizing this behavior based on the consumer's needs.

  const getOrganizationProjects = useCallback(async () => {
    try {
      const res = await getOrganizationProjectsQueryCall();
      setOrganizationProjects(res.data.items);
+     return res.data.items; // Return the items for consistency
    } catch (error) {
      console.log(error);
+     throw error; // Propagate error for consistent error handling
    }
  }, [getOrganizationProjectsQueryCall, setOrganizationProjects]);

Committable suggestion skipped: line range outside the PR's diff.


return {
editOrganizationProjectSetting,
editOrganizationProjectSettingLoading,
editOrganizationProject,
editOrganizationProjectLoading,
getOrganizationProject,
getOrganizationProjectLoading,
getOrganizationProjects,
getOrganizationProjectsLoading,
organizationProjects,
};
}
2 changes: 1 addition & 1 deletion apps/web/app/interfaces/IDailyPlan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ export enum DailyPlanStatusEnum {
COMPLETED = 'completed'
}

export type IDailyPlanMode = 'today' | 'tomorow' | 'custom';
export type IDailyPlanMode = 'today' | 'tomorrow' | 'custom';
2 changes: 1 addition & 1 deletion apps/web/app/interfaces/ITask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type ITeamTask = {
estimateMinutes?: number;
dueDate: string;
startDate?: string | null;
projectId: string;
projectId: string | null;
public: boolean;
taskStatusId?: string;
resolvedAt?: string;
Expand Down
28 changes: 26 additions & 2 deletions apps/web/app/services/client/api/organization-projects.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { IProject } from '@app/interfaces';
import { put } from '../axios';
import { IProject, PaginationResponse } from '@app/interfaces';
import { get, put } from '../axios';
import qs from 'qs';
import { getOrganizationIdCookie, getTenantIdCookie } from '@/app/helpers';

export function editOrganizationProjectSettingAPI(id: string, data: any, tenantId?: string) {
return put<any>(`/organization-projects/setting/${id}`, data, {
Expand All @@ -12,3 +14,25 @@ export function editOrganizationProjectAPI(id: string, data: any, tenantId?: str
tenantId
});
}

export function getOrganizationProjectAPI(id: string, tenantId?: string) {
return get<IProject>(`/organization-projects/${id}`, {
tenantId
});
}

export function getOrganizationProjectsAPI() {

const organizationId = getOrganizationIdCookie();
const tenantId = getTenantIdCookie();

CREDO23 marked this conversation as resolved.
Show resolved Hide resolved
const obj = {
'where[organizationId]': organizationId,
'where[tenantId]': tenantId,
}
const query = qs.stringify(obj);

return get<PaginationResponse<IProject>>(`/organization-projects?${query}`, {
tenantId
});
}
43 changes: 43 additions & 0 deletions apps/web/app/services/server/requests/organization-projects.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import qs from 'qs';
import { serverFetch } from '../fetch';
import { IProject, PaginationResponse } from '@/app/interfaces';

export function editOrganizationProjectsSettingsRequest({
id,
Expand Down Expand Up @@ -39,3 +41,44 @@ export function editOrganizationProjectsRequest({
tenantId
});
}

export function getOrganizationProjectRequest({
id,
tenantId,
bearer_token
}: {
id: string;
tenantId: string;
bearer_token: string;
}) {
return serverFetch<IProject>({
path: `/organization-projects/${id}`,
method: 'GET',
bearer_token,
tenantId
});
}

export function getOrganizationProjectsRequest({
tenantId,
organizationId,
bearer_token
}: {
tenantId: string;
bearer_token: string;
organizationId : string;
}) {

const obj = {
'where[organizationId]': organizationId,
'where[tenantId]': tenantId,
}
const query = qs.stringify(obj);

return serverFetch<PaginationResponse<IProject>>({
path: `/organization-projects?${query}`,
method: 'GET',
bearer_token,
tenantId
});
}
4 changes: 4 additions & 0 deletions apps/web/app/stores/organization-projects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { atom } from "jotai";
import { IProject } from "../interfaces";

export const organizationProjectsState = atom<IProject[]>([])
2 changes: 1 addition & 1 deletion apps/web/components/pages/kanban/menu-kanban-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export default function MenuKanbanCard({ item: task, member }: { item: ITeamTask
<PlanTask planMode="today" taskId={task.id} chooseMember={true} />
</li>
<li className="font-normal flex justify-between capitalize hover:bg-secondary-foreground/20 w-full text-left whitespace-nowrap text-sm hover:font-semibold hover:transition-all py-1 px-2">
<PlanTask planMode="tomorow" taskId={task.id} chooseMember={true} />
<PlanTask planMode="tomorrow" taskId={task.id} chooseMember={true} />
</li>
<li className="font-normal flex justify-between capitalize hover:bg-secondary-foreground/20 w-full text-left whitespace-nowrap text-sm hover:font-semibold hover:transition-all py-1 px-2">
<PlanTask planMode="custom" taskId={task.id} chooseMember={true} />
Expand Down
Loading
Loading