Skip to content

Commit

Permalink
Merge pull request #33 from CambioML/jojo-branch
Browse files Browse the repository at this point in the history
update for eps Rag, add delete Project
  • Loading branch information
Cambio ML authored Aug 23, 2024
2 parents 0cdb626 + 2e8a70d commit 050491f
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 37 deletions.
22 changes: 22 additions & 0 deletions app/actions/sustainabilityReport/deleteProjects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import axios from 'axios';

interface IParams {
userId: string;
projectIds: string[];
}

export const deleteProjects = async ({ userId, projectIds }: IParams) => {
const data = {
userId: userId,
projectIds: projectIds,
};
return await axios
.post(process.env.NEXT_PUBLIC_PORTFOLIO_INSIGHT_API_URL + '/delete-projects', data)
.then((response) => {
return response.data;
})
.catch((error) => {
console.error('Error adding attribute. Please try again.');
throw error;
});
};
33 changes: 33 additions & 0 deletions app/components/SustainabilityReport/ProjectContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import useSustainabilityReportDeleteModal from '@/app/hooks/sustainabilityReport/useSustainabilityReportDeleteModal';
import { Project } from '@/app/types/SustainabilityReportTypes';
import { Typography } from '@material-tailwind/react';
import { X } from '@phosphor-icons/react';

interface ProjectContainerProps {
project: Project;
}

const ProjectContainer = ({ project }: ProjectContainerProps) => {
const sustainabilityReportDeleteModal = useSustainabilityReportDeleteModal();

const handleDeleteProject = () => {
console.log('Deleting project:', project.name);
sustainabilityReportDeleteModal.setDeleteItem(project);
sustainabilityReportDeleteModal.onOpen();
};
return (
<div className="relative px-2 py-1 w-full overflow-hidden flex items-center justify-center group">
<Typography variant="paragraph" color="blue-gray" className="font-normal w-full overflow-auto text-nowrap pr-10">
{project.name}
</Typography>
<div
onClick={handleDeleteProject}
className="absolute right-2 p-2 rounded-md cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity duration-300 hover:bg-blue-gray-50"
>
<X size={16} />
</div>
</div>
);
};

export default ProjectContainer;
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useState } from 'react';
import { FieldValues, SubmitHandler, useForm } from 'react-hook-form';
import { isAttribute, isReport } from '@/app/types/SustainabilityReportTypes';
import { isAttribute, isReport, isProject } from '@/app/types/SustainabilityReportTypes';

import FormModal from '../FormModal';
import Heading from '../../Heading';
Expand All @@ -13,30 +13,43 @@ import useSustainabilityStore from '@/app/hooks/sustainabilityReport/sustainabil
import { deleteAttribute } from '@/app/actions/sustainabilityReport/deleteAttribute';
import { deleteReports } from '@/app/actions/sustainabilityReport/deleteReports';
import useFetchSustainabilityData from '@/app/hooks/sustainabilityReport/useFetchSustainabilityData';
import { deleteProjects } from '@/app/actions/sustainabilityReport/deleteProjects';

const SustainabilityReportDeleteModal = () => {
const SustainabilityReportDeleteModal = useSustainabilityReportDeleteModal();
const [isLoading, setIsLoading] = useState(false);
const { userId, deleteStoreAttribute } = useSustainabilityStore();
const { userId, deleteStoreAttribute, deleteStoreProject, deleteStoreReport } = useSustainabilityStore();
const { fetchAttributesThenProjects } = useFetchSustainabilityData();
const { handleSubmit, reset } = useForm<FieldValues>({});

const onSubmit: SubmitHandler<FieldValues> = async () => {
try {
setIsLoading(true);
const deleteItemId = SustainabilityReportDeleteModal.deleteItem?.id;
console.log('DELETING', deleteItemId);
if (!deleteItemId) {
throw new Error('Delete ID is missing');
}
if (isAttribute(SustainabilityReportDeleteModal.deleteItem)) {
await deleteAttribute({ userId, attributeId: deleteItemId });
deleteStoreAttribute(deleteItemId);
if (isProject(SustainabilityReportDeleteModal.deleteItem)) {
console.log('Deleting project', deleteItemId, userId);
await deleteProjects({
userId,
projectIds: [deleteItemId],
});
deleteStoreProject(deleteItemId);
} else if (isReport(SustainabilityReportDeleteModal.deleteItem)) {
console.log('deleting report');

await deleteReports({
userId,
projectId: SustainabilityReportDeleteModal.projectId,
reportIds: [deleteItemId],
});
deleteStoreReport(deleteItemId);
} else if (isAttribute(SustainabilityReportDeleteModal.deleteItem)) {
console.log('deleting attribute');
await deleteAttribute({ userId, attributeId: deleteItemId });
deleteStoreAttribute(deleteItemId);
}
SustainabilityReportDeleteModal.onClose();
fetch;
Expand Down
10 changes: 10 additions & 0 deletions app/hooks/sustainabilityReport/sustainabilityReportStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ interface SustainabilityStoreState {
addAttributes: (newAttributes: Attribute[]) => void;
updateStoreAttribute: (attributeId: string, newAttribute: Attribute) => void;
deleteStoreAttribute: (attributeId: string) => void;
deleteStoreReport: (reportId: string) => void;
deleteStoreProject: (projectId: string) => void;
addReportsToAdd: (newReports: File[]) => void;
setReportsToAdd: (newReports: File[]) => void;
updateStatus: (projectId: string, status: GenerationStatus) => void;
Expand All @@ -34,6 +36,10 @@ const useSustainabilityStore = create<SustainabilityStoreState>((set) => ({
const filteredProjects = newProjects.filter((project) => !existingProjectIds.has(project.id));
return { projects: [...state.projects, ...filteredProjects] };
}),
deleteStoreProject: (projectId) =>
set((state) => ({
projects: state.projects.filter((project) => project.id !== projectId),
})),
addAttributes: (newAttributes) =>
set((state) => {
const existingAttributeIds = new Set(state.attributes.map((attribute) => attribute.id));
Expand All @@ -57,6 +63,10 @@ const useSustainabilityStore = create<SustainabilityStoreState>((set) => ({
isLoading: false,
addReportsToAdd: (newReports) => set((state) => ({ reportsToAdd: [...state.reportsToAdd, ...newReports] })),
setReportsToAdd: (newReports) => set({ reportsToAdd: newReports }),
deleteStoreReport: (reportId) =>
set((state) => ({
reports: state.reports.filter((report) => report.id !== reportId),
})),
updateResults: (projectId, results) =>
set((state) => ({
projects: state.projects.map((project) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Attribute, Report } from '@/app/types/SustainabilityReportTypes';
import { Attribute, Project, Report } from '@/app/types/SustainabilityReportTypes';
import { create } from 'zustand';

interface SustainabilityReportDeleteModalStore {
isOpen: boolean;
deleteItem: Attribute | Report | null;
deleteItem: Attribute | Report | Project | null;
projectId: string;
onOpen: () => void;
onClose: () => void;
setDeleteItem: (deleteItem: Attribute | Report) => void;
setDeleteItem: (deleteItem: Attribute | Report | Project) => void;
setProjectId: (projectId: string) => void;
}

Expand All @@ -17,7 +17,7 @@ const useSustainabilityReportDeleteModal = create<SustainabilityReportDeleteModa
projectId: '',
onOpen: () => set({ isOpen: true }),
onClose: () => set({ isOpen: false }),
setDeleteItem: (deleteItem: Attribute | Report) => set({ deleteItem }),
setDeleteItem: (deleteItem: Attribute | Report | Project) => set({ deleteItem }),
setProjectId: (projectId: string) => set({ projectId }),
}));

Expand Down
61 changes: 39 additions & 22 deletions app/pages/sustainabilityreports/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import SustainabilityReportDeleteModal from '@/app/components/modals/sustainabil
import useSustainabilityReportDeleteModal from '@/app/hooks/sustainabilityReport/useSustainabilityReportDeleteModal';
import SustainabilityReportAddFileModal from '@/app/components/modals/sustainabilityReport/SustainabilityReportAddFileModal';
import FilesContainer from '@/app/components/SustainabilityReport/FilesContainer';
import ProjectContainer from '@/app/components/SustainabilityReport/ProjectContainer';

function Page() {
const { projects, attributes, isLoading, setIsLoading, updateResults, updateStatus, userId, setUserId } =
Expand Down Expand Up @@ -157,6 +158,17 @@ function Page() {
);
};

const checkFilesForProject = (project: Project): boolean => {
return project.reports.length > 0;
};

const checkFilesForAllProjects = () => {
for (const project of projects) {
if (checkFilesForProject(project)) return true;
}
return false;
};

const checkNewAttributes = () => {
for (const project of projects) {
if (checkNewAttributesForProject(project)) return true;
Expand Down Expand Up @@ -194,15 +206,21 @@ function Page() {
<div className="flex gap-2">
<Button
onClick={handleGenerateNewAll}
disabled={isLoading || attributes.length === 0 || projects.length === 0 || !checkNewAttributes()}
disabled={
isLoading ||
attributes.length === 0 ||
projects.length === 0 ||
!checkNewAttributes() ||
!checkFilesForAllProjects()
}
className="flex gap-2 bg-blue-900"
>
Generate New
<Sparkle size={16} className="shrink-0" />
</Button>
<Button
onClick={handleRegenerateAll}
disabled={isLoading || attributes.length === 0 || projects.length === 0}
disabled={isLoading || attributes.length === 0 || projects.length === 0 || !checkFilesForAllProjects()}
className="flex gap-2 bg-blue-900"
>
Regenerate All
Expand Down Expand Up @@ -270,36 +288,30 @@ function Page() {
</tr>
</thead>
<tbody>
{projects.map(({ projectResults, status, name, reports, id }, index) => {
{projects.map((project, index) => {
const isLast = index === projects.length - 1;
const classes = isLast ? 'p-4' : 'p-4 border-b border-blue-gray-50';

return (
<tr key={index} className="border-b border-blue-gray-100 max-h-[300px]">
<td className={`${classes} sticky left-0 z-10 bg-white`}>
<Typography
variant="paragraph"
color="blue-gray"
className="font-normal w-full overflow-auto text-nowrap"
>
{name}
</Typography>
<ProjectContainer project={project} />
</td>
<td className={`${classes} w-[250px] h-auto max-h-[300px] overflow-y-auto`}>
<FilesContainer reports={reports} projectId={id} />
<FilesContainer reports={project.reports} projectId={project.id} />
</td>

{attributes.map((attribute: Attribute, index: number) => (
<td className={`${classes} max-h-[300px] overflow-y-auto`} key={index + name}>
{attribute.id in projectResults && isNotEmpty(projectResults[attribute.id]) ? (
<div className="max-h-[300px] overflow-y-auto">{projectResults[attribute.id]}</div>
<td className={`${classes} max-h-[300px] overflow-y-auto`} key={index + project.name}>
{attribute.id in project.projectResults && isNotEmpty(project.projectResults[attribute.id]) ? (
<div className="max-h-[300px] overflow-y-auto">{project.projectResults[attribute.id]}</div>
) : (
<div
className={`w-full h-[32px] rounded-lg bg-gray-300 flex justify-center items-center text-gray-600 ${
status === GenerationStatus.GENERATING && 'bg-gray-400 animate-pulse'
project.status === GenerationStatus.GENERATING && 'bg-gray-400 animate-pulse'
}`}
>
{status !== GenerationStatus.GENERATING && 'None'}
{project.status !== GenerationStatus.GENERATING && 'None'}
</div>
)}
</td>
Expand All @@ -311,23 +323,28 @@ function Page() {
<Button
className="bg-blue-900"
size="sm"
disabled={isLoading || !checkNewAttributesForProject(projects[index])}
disabled={
isLoading ||
!checkNewAttributesForProject(projects[index]) ||
!checkFilesForProject(projects[index])
}
onClick={() => handleGenerateNew(projects[index].id)}
loading={status === GenerationStatus.GENERATING}
loading={project.status === GenerationStatus.GENERATING}
>
<span className="flex gap-2">
{status !== GenerationStatus.GENERATING && 'New'} <Sparkle size={16} />
{project.status !== GenerationStatus.GENERATING && 'New'} <Sparkle size={16} />
</span>
</Button>
<Button
className="bg-blue-900"
size="sm"
disabled={isLoading}
disabled={isLoading || !checkFilesForProject(projects[index])}
onClick={() => handleRegenerate(projects[index].id)}
loading={status === GenerationStatus.GENERATING}
loading={project.status === GenerationStatus.GENERATING}
>
<span className="flex gap-2">
{status !== GenerationStatus.GENERATING && 'All'} <ArrowsCounterClockwise size={16} />
{project.status !== GenerationStatus.GENERATING && 'All'}{' '}
<ArrowsCounterClockwise size={16} />
</span>
</Button>
</div>
Expand Down
26 changes: 20 additions & 6 deletions app/types/SustainabilityReportTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,16 @@ export type RawReport = {
};

export function isReport(obj: any): obj is Report {
return obj && typeof obj.id === 'string' && typeof obj.name === 'string';
// Ensure obj has the Report-specific fields
return (
obj &&
typeof obj.id === 'string' &&
typeof obj.name === 'string' &&
!('projectResults' in obj) && // Ensure it doesn't have Project-specific fields
!('reports' in obj) &&
!('type' in obj) && // Ensure it doesn't have Attribute-specific fields
!('description' in obj)
);
}

export function isProject(obj: any): obj is Project {
Expand All @@ -55,13 +64,18 @@ export function isProject(obj: any): obj is Project {
typeof obj.id === 'string' &&
typeof obj.name === 'string' &&
typeof obj.description === 'string' &&
typeof obj.projectResults === 'object' &&
Array.isArray(obj.reports) &&
obj.reports.every(isReport) &&
Object.values(GenerationStatus).includes(obj.status)
typeof obj.projectResults === 'object'
);
}

export function isAttribute(obj: any): obj is Attribute {
return obj && typeof obj.id === 'string' && typeof obj.name === 'string' && typeof obj.description === 'string';
return (
obj &&
typeof obj.id === 'string' &&
typeof obj.name === 'string' &&
typeof obj.description === 'string' &&
!('projectResults' in obj) && // Ensure it doesn't have Project-specific fields
!('reports' in obj) && // Ensure it doesn't have Project-specific fields
!('status' in obj)
); // Ensure it doesn't have Project-specific fields
}

0 comments on commit 050491f

Please sign in to comment.