Skip to content

Commit

Permalink
feat: implement column-based layout for workspace planner
Browse files Browse the repository at this point in the history
  • Loading branch information
MirzaHanan committed Dec 29, 2024
1 parent 1b4c015 commit 32f81e0
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 51 deletions.
226 changes: 175 additions & 51 deletions src/people/WorkSpacePlanner/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,99 +3,223 @@ import { observer } from 'mobx-react-lite';
import { useParams } from 'react-router-dom';
import { EuiLoadingSpinner } from '@elastic/eui';
import styled from 'styled-components';
import { useBountyCardStore } from 'store/bountyCard';
import { BountyCard } from 'store/interface';
import history from 'config/history';
import { useStores } from '../../store';
import { colors } from '../../config';
import { useBountyCardStore } from '../../store/bountyCard';
import { WorkspacePlannerHeader } from './WorkspacePlannerHeader';
import BountyCardComp from './BountyCard';

const PlannerContainer = styled.div`
// Styled Components
const BoardContainer = styled.div`
padding: 0;
height: calc(100vh - 65px);
background: ${colors.light.grayish.G950};
overflow-y: auto;
overflow-x: hidden;
`;

const ContentArea = styled.div`
const LoadingContainer = styled.div`
display: flex;
justify-content: center;
align-items: center;
height: 100%;
`;

const BoardContent = styled.div`
width: 90%;
margin: 20px auto;
background: white;
border-radius: 8px;
min-height: 500px;
text-align: center;
padding: 20px;
`;

const BountyCardList = styled.ul`
list-style: none;
padding: 0;
margin: 20px 0;
const BoardLayout = styled.div`
display: flex;
gap: 1rem;
padding: 1rem;
overflow-x: auto;
height: calc(100% - 60px);
background: white;
&::-webkit-scrollbar {
height: 8px;
}
&::-webkit-scrollbar-track {
background: ${colors.light.grayish.G900};
}
&::-webkit-scrollbar-thumb {
background: ${colors.light.grayish.G800};
border-radius: 4px;
}
`;

const BoardColumn = styled.div`
flex: 0 0 320px;
border-radius: 8px;
display: flex;
flex-direction: column;
max-height: 100%;
`;

const BoardColumnHeader = styled.div`
padding: 1rem;
background: ${colors.light.grayish.G800};
border-radius: 8px 8px 0 0;
border-bottom: 1px solid ${colors.light.grayish.G700};
position: sticky;
top: 0;
color: black;
`;

const ColumnHeading = styled.h3`
margin: 0;
font-size: 1rem;
font-weight: 600;
display: flex;
align-items: center;
justify-content: space-between;
`;

const ItemCounter = styled.span`
font-size: 0.875rem;
color: ${colors.light.grayish.G400};
`;

const BoardColumnContent = styled.div`
padding: 0.5rem;
overflow-y: auto;
flex: 1;
&::-webkit-scrollbar {
width: 6px;
}
li {
&::-webkit-scrollbar-track {
background: ${colors.light.grayish.G900};
}
&::-webkit-scrollbar-thumb {
background: ${colors.light.grayish.G800};
margin: 10px 0;
padding: 15px;
border-radius: 5px;
text-align: left;
border-radius: 3px;
}
`;

const LoadMoreTrigger = styled.button`
width: 100%;
padding: 0.5rem;
background: ${colors.light.grayish.G800};
color: white;
border: none;
border-top: 1px solid ${colors.light.grayish.G700};
cursor: pointer;
transition: background 0.2s;
&:hover {
background: ${colors.light.grayish.G700};
}
`;

const WorkspacePlanner = () => {
const ErrorMessage = styled.p`
color: ${colors.light.red1};
padding: 1rem;
text-align: center;
`;

const BOARD_COLUMNS = [
{ key: 'Todo', label: 'To Do' },
{ key: 'Assigned', label: 'In Progress' },
{ key: 'Complete', label: 'Complete' },
{ key: 'Paid', label: 'Paid' }
] as const;

const WorkspaceBoard: React.FC = () => {
const { uuid } = useParams<{ uuid: string }>();
const { main } = useStores();
const [loading, setLoading] = useState(true);
const [workspaceData, setWorkspaceData] = useState<any>(null);
const bountyCardStore = useBountyCardStore(uuid);
const [isInitializing, setIsInitializing] = useState(true);
const [workspaceDetails, setWorkspaceDetails] = useState<any>(null);
const boardStore = useBountyCardStore(uuid);

useEffect(() => {
const fetchWorkspaceData = async () => {
const initializeWorkspace = async () => {
if (!uuid) return;
const data = await main.getUserWorkspaceByUuid(uuid);
setWorkspaceData(data);
bountyCardStore.loadWorkspaceBounties();
setLoading(false);
const details = await main.getUserWorkspaceByUuid(uuid);
setWorkspaceDetails(details);
boardStore.loadWorkspaceBounties();
setIsInitializing(false);
};
initializeWorkspace();
}, [main, uuid, boardStore]);

fetchWorkspaceData();
}, [main, uuid, bountyCardStore]);

if (loading) {
if (isInitializing) {
return (
<PlannerContainer style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<EuiLoadingSpinner size="xl" />
</PlannerContainer>
<BoardContainer>
<LoadingContainer>
<EuiLoadingSpinner size="xl" />
</LoadingContainer>
</BoardContainer>
);
}

const onclick = (bountyId: string) => {
const boardSections = {
Todo: boardStore.todoItems,
Assigned: boardStore.assignedItems,
Complete: boardStore.completedItems,
Paid: boardStore.paidItems
};

const navigateToBounty = (bountyId: string): void => {
history.push(`/bounty/${bountyId}`);
};

return (
<PlannerContainer>
<WorkspacePlannerHeader workspace_uuid={uuid} workspaceData={workspaceData} />
<ContentArea>
<BoardContainer>
<WorkspacePlannerHeader workspace_uuid={uuid} workspaceData={workspaceDetails} />
<BoardContent>
<h1>Welcome to the new Workspace Planner</h1>
{bountyCardStore.loading ? (
<EuiLoadingSpinner size="m" />
) : bountyCardStore.error ? (
<p style={{ color: 'red' }}>{bountyCardStore.error}</p>
) : (
<BountyCardList>
{bountyCardStore.bountyCards.map((card: BountyCard) => (
<BountyCardComp key={card.id} {...card} onclick={onclick} />
))}
</BountyCardList>
)}
{bountyCardStore.pagination.currentPage * bountyCardStore.pagination.pageSize <
bountyCardStore.pagination.total && (
<button onClick={() => bountyCardStore.loadNextPage()}>Load More</button>
)}
</ContentArea>
</PlannerContainer>
<BoardLayout>
{BOARD_COLUMNS.map(({ key, label }: { key: string; label: string }) => (
<BoardColumn key={key}>
<BoardColumnHeader>
<ColumnHeading>
{label}
<ItemCounter>({boardSections[key]?.length || 0})</ItemCounter>
</ColumnHeading>
</BoardColumnHeader>

<BoardColumnContent>
{boardStore.loading ? (
<LoadingContainer>
<EuiLoadingSpinner size="m" />
</LoadingContainer>
) : boardStore.error ? (
<ErrorMessage>{boardStore.error}</ErrorMessage>
) : (
boardSections[key]?.map((bounty: BountyCard) => (
<BountyCardComp
key={bounty.id}
{...bounty}
onclick={() => navigateToBounty(bounty.id)}
/>
))
)}
</BoardColumnContent>

{key === 'Todo' && boardStore.hasMorePages && (
<LoadMoreTrigger onClick={() => boardStore.loadNextPage()}>
Load More
</LoadMoreTrigger>
)}
</BoardColumn>
))}
</BoardLayout>
</BoardContent>
</BoardContainer>
);
};

export default observer(WorkspacePlanner);
export default observer(WorkspaceBoard);
4 changes: 4 additions & 0 deletions src/store/bountyCard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ export class BountyCardStore {
@computed get paidItems() {
return this.bountyCards.filter((card: BountyCard) => card.status === 'Paid');
}

@computed get hasMorePages(): boolean {
return this.pagination.currentPage * this.pagination.pageSize < this.pagination.total;
}
}

export const useBountyCardStore = (workspaceId: string) =>
Expand Down

0 comments on commit 32f81e0

Please sign in to comment.