Skip to content

Commit

Permalink
Merge pull request #30 from CambioML/jojo-branch
Browse files Browse the repository at this point in the history
add projects cont'd; addFile functionality
  • Loading branch information
Cambio ML authored Aug 20, 2024
2 parents 141521f + 123c1a5 commit a30c2d2
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 17 deletions.
26 changes: 26 additions & 0 deletions app/components/SustainabilityReport/FileTag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { Typography } from '@material-tailwind/react';
import { Report } from '@/app/types/SustainabilityReportTypes';

function truncateMiddle(text: string, maxLength = 25) {
if (text.length <= maxLength) return text;
const start = text.substring(0, Math.ceil(maxLength / 2));
const end = text.substring(text.length - Math.floor(maxLength / 2));
return `${start}...${end}`;
}

interface FileTagProps {
report: Report;
}

const FileTag = ({ report }: FileTagProps) => {
return (
<div className="bg-blue-gray-50 px-2 py-1 rounded-full w-full overflow-hidden flex items-center justify-center">
<Typography variant="paragraph" color="blue-gray" className="font-normal whitespace-nowrap overflow-hidden">
{truncateMiddle(report.name, 25)}
</Typography>
</div>
);
};

export default FileTag;
36 changes: 36 additions & 0 deletions app/components/SustainabilityReport/FilesContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Report } from '@/app/types/SustainabilityReportTypes';
import FileTag from './FileTag';
import useSustainabilityReportAddFileModal from '@/app/hooks/sustainabilityReport/useSustainabilityReportAddFileModal';
import { Plus } from '@phosphor-icons/react';

interface FilesContainerProps {
reports: Report[];
projectId: string;
}

const FilesContainer = ({ reports, projectId }: FilesContainerProps) => {
const sustainabilityReportAddFileModal = useSustainabilityReportAddFileModal();

const handleAddFile = () => {
sustainabilityReportAddFileModal.setProjectId(projectId);
sustainabilityReportAddFileModal.onOpen();
};

return (
<div className="relative flex flex-wrap gap-2 max-w-[250px] h-full overflow-y-auto p-2 rounded group">
<div
className="absolute hidden top-0 right-2 p-1 cursor-pointer bg-blue-gray-50 hover:bg-gray-300 rounded-lg group-hover:block"
onClick={handleAddFile}
>
<Plus size={16} />
</div>
<div className="flex flex-col gap-2 py-6">
{reports.map((report, i) => (
<FileTag key={i} report={report} />
))}
</div>
</div>
);
};

export default FilesContainer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
'use client';

import { useState } from 'react';
import useSustainabilityReportAddFileModal, {
AddFileModalState,
} from '@/app/hooks/sustainabilityReport/useSustainabilityReportAddFileModal';
import FormModal from '../FormModal';
import Heading from '../../Heading';
import { toast } from 'react-hot-toast';
import Dropzone from '../../SustainabilityReport/Dropzone';
import useSustainabilityStore from '@/app/hooks/sustainabilityReport/sustainabilityReportStore';
import { CloudArrowUp } from '@phosphor-icons/react';
import { uploadFile } from '@/app/actions/sustainabilityReport/uploadFile';
import { AxiosError } from 'axios';
import useFetchSustainabilityData from '@/app/hooks/sustainabilityReport/useFetchSustainabilityData';
import { FieldValues, SubmitHandler, useForm } from 'react-hook-form';

const SustainabilityReportAddFileModal = () => {
const SustainabilityReportAddFileModal = useSustainabilityReportAddFileModal();
const [isLoading, setIsLoading] = useState(false);
const { reportsToAdd, setReportsToAdd, userId } = useSustainabilityStore();
const { fetchAttributesThenProjects } = useFetchSustainabilityData();

const { handleSubmit, reset } = useForm<FieldValues>({});

const onSubmit: SubmitHandler<FieldValues> = async () => {
try {
setIsLoading(true);
SustainabilityReportAddFileModal.setAddFileModalState(AddFileModalState.UPLOADING);
console.log('Uploading reports:', reportsToAdd);

const uploadResponses = await Promise.all(
reportsToAdd.map((report) =>
uploadFile({
file: report,
projectId: SustainabilityReportAddFileModal.projectId,
userId: userId,
})
)
);

console.log('Uploads complete', uploadResponses);
await fetchAttributesThenProjects();
} catch (error) {
if (error instanceof AxiosError) {
console.error('AxiosError occurred:', {
message: error.message,
code: error.code,
response: error.response
? {
status: error.response.status,
data: error.response.data,
}
: null,
});

toast.error('A network or server error occurred. Please try again.');
} else {
console.error('An error occurred:', error);
toast.error('Add company failed. Please try again.');
}
} finally {
SustainabilityReportAddFileModal.setAddFileModalState(AddFileModalState.ADD_FILES);
SustainabilityReportAddFileModal.onClose();
setReportsToAdd([]);
setIsLoading(false);
reset();
}
};

const handleClose = () => {
setReportsToAdd([]);
SustainabilityReportAddFileModal.onClose();
};

const bodyContent = (
<div className="flex flex-col gap-4">
<Heading title="Add Files" subtitle="" center />
{SustainabilityReportAddFileModal.addFileModalState === AddFileModalState.ADD_FILES && (
<>
<Dropzone />
{reportsToAdd.length > 0 && (
<div className="flex flex-wrap gap-2 max-h-[100px] overflow-y-auto">
{reportsToAdd.map((report, index) => (
<div key={index} className="text-gray-800 whitespace-nowrap bg-gray-200 rounded-full px-2 py-1">
{report.name}
</div>
))}
</div>
)}
</>
)}
{SustainabilityReportAddFileModal.addFileModalState === AddFileModalState.UPLOADING && (
<div className="flex flex-col justify-center items-center gap-4 text-xl">
Uploading Files
<CloudArrowUp size={40} className="animate-pulse" />
</div>
)}
</div>
);

return (
<FormModal
disabled={isLoading}
isOpen={SustainabilityReportAddFileModal.isOpen}
title=""
actionLabel={`Add File ${reportsToAdd.length > 0 ? `(${reportsToAdd.length})` : ''}`}
onClose={handleClose}
onSubmit={handleSubmit(onSubmit)}
body={bodyContent}
actionDisabled={reportsToAdd.length === 0}
/>
);
};

export default SustainabilityReportAddFileModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { create } from 'zustand';

export enum AddFileModalState {
ADD_FILES,
UPLOADING,
SUCCESS,
}

interface SustainabilityReportAddFileModalStore {
isOpen: boolean;
content: React.ReactElement | null;
addFileModalState: AddFileModalState;
projectId: string;
onOpen: () => void;
onClose: () => void;
setContent: (content: React.ReactElement) => void;
setProjectId: (projectId: string) => void;
setAddFileModalState: (addFileModalState: AddFileModalState) => void;
}

const useSustainabilityReportAddFileModal = create<SustainabilityReportAddFileModalStore>((set) => ({
isOpen: false,
content: null,
addFileModalState: AddFileModalState.ADD_FILES,
projectId: '',
onOpen: () => set({ isOpen: true }),
onClose: () => set({ isOpen: false }),
setContent: (content) => set({ content }),
setProjectId: (projectId) => set({ projectId }),
setAddFileModalState: (addFileModalState) => set({ addFileModalState }),
}));

export default useSustainabilityReportAddFileModal;
31 changes: 14 additions & 17 deletions app/pages/sustainabilityreports/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import SustainabilityUpdateAttributeModal from '@/app/components/modals/sustaina
import useSustainabilityUpdateAttributeModal from '@/app/hooks/sustainabilityReport/useSustainabilityUpdateAttributeModal';
import SustainabilityReportDeleteModal from '@/app/components/modals/sustainabilityReport/SustainabilityReportDeleteModal';
import useSustainabilityReportDeleteModal from '@/app/hooks/sustainabilityReport/useSustainabilityReportDeleteModal';
import SustainabilityReportAddFileModal from '@/app/components/modals/sustainabilityReport/SustainabilityReportAddFileModal';
import FilesContainer from '@/app/components/SustainabilityReport/FilesContainer';

function Page() {
const { projects, attributes, isLoading, setIsLoading, updateResults, updateStatus, userId, setUserId } =
Expand Down Expand Up @@ -84,7 +86,6 @@ function Page() {
}
}
const response = await generateAttributes({ userId, projectIds: projectIds, rerunAll });
console.log;
const results = response.attributesGenerated;

for (const projectId in results) {
Expand Down Expand Up @@ -149,13 +150,16 @@ function Page() {
return false;
}

const checkNewAttributesForReport = (project: Project): boolean => {
return attributes.length > Object.keys(project.projectResults).length;
const checkNewAttributesForProject = (project: Project): boolean => {
return (
attributes.length >
Object.keys(project.projectResults).filter((key) => project.projectResults[key] !== null).length
);
};

const checkNewAttributes = () => {
for (const project of projects) {
if (checkNewAttributesForReport(project)) return true;
if (checkNewAttributesForProject(project)) return true;
}
return false;
};
Expand All @@ -177,6 +181,7 @@ function Page() {
<SustainabilityReportProjectModal />
<SustainabilityUpdateAttributeModal />
<SustainabilityReportDeleteModal />
<SustainabilityReportAddFileModal />
<Title label="Sustainability Reports" />
<div className="mt-8 flex w-full justify-between">
<Button
Expand Down Expand Up @@ -265,7 +270,7 @@ function Page() {
</tr>
</thead>
<tbody>
{projects.map(({ projectResults, status, name, reports }, index) => {
{projects.map(({ projectResults, status, name, reports, id }, index) => {
const isLast = index === projects.length - 1;
const classes = isLast ? 'p-4' : 'p-4 border-b border-blue-gray-50';

Expand All @@ -280,16 +285,8 @@ function Page() {
{name}
</Typography>
</td>
<td className={`${classes} w-[250px]`}>
<div className="flex flex-wrap gap-2 max-w-[250px] max-h-[200px] overflow-y-auto">
{reports.map((report, i) => (
<div key={i} className="bg-blue-gray-50 px-2 py-1 rounded-full w-fit">
<Typography variant="paragraph" color="blue-gray" className="font-normal whitespace-nowrap">
{report.name}
</Typography>
</div>
))}
</div>
<td className={`${classes} w-[250px] h-auto`}>
<FilesContainer reports={reports} projectId={id} />
</td>

{attributes.map((attribute: Attribute, index: number) => (
Expand All @@ -300,7 +297,7 @@ function Page() {
<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'}`}
>
{attribute.name in projectResults && 'None'}
{status !== GenerationStatus.GENERATING && 'None'}
</div>
)}
</td>
Expand All @@ -312,7 +309,7 @@ function Page() {
<Button
className="bg-blue-900"
size="sm"
disabled={isLoading || !checkNewAttributesForReport(projects[index])}
disabled={isLoading || !checkNewAttributesForProject(projects[index])}
onClick={() => handleGenerateNew(projects[index].id)}
loading={status === GenerationStatus.GENERATING}
>
Expand Down

0 comments on commit a30c2d2

Please sign in to comment.