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

feat: Implement dashboard tab section #52

Merged
merged 40 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
fbfadcf
feat: margin props
santhitak Mar 27, 2024
81fef01
feat: text variant small
santhitak Mar 27, 2024
70e1fe0
feat: badge button
santhitak Mar 27, 2024
cea6039
feat: add margin prop to Box
santhitak Mar 27, 2024
de3f840
feat: add margin prop to Box
santhitak Mar 27, 2024
f2f8e87
feat: add logo to brand name
santhitak Mar 27, 2024
0cf195a
feat: plan badge
santhitak Mar 27, 2024
7768d58
feat: dashboard tab
santhitak Mar 27, 2024
f5caa38
feat: add current plan
santhitak Mar 27, 2024
c447a7a
feat: test github workflow
santhitak Mar 27, 2024
fe9d21b
feat: test github workflow
santhitak Mar 27, 2024
4ae0f5a
fix: pipeline
santhitak Mar 27, 2024
92af4f8
fix: remove context declaration
santhitak Mar 27, 2024
c862797
feat: make use of deploy_link.sh
santhitak Mar 27, 2024
5eef35a
fix: remove github declaration
santhitak Mar 27, 2024
a6f6a1d
fix: shell script path
santhitak Mar 27, 2024
776ad12
fix: have deployment log out of workflow folder
santhitak Mar 27, 2024
e382a0d
fix: pipeline
santhitak Mar 27, 2024
410b6ad
fix: pipeline
santhitak Mar 27, 2024
47ad54d
fix: have deployment log out of workflow folder
santhitak Mar 27, 2024
7afa813
fix: remove github declaration
santhitak Mar 27, 2024
89d6d98
fix: change typo link to dep_link
santhitak Mar 27, 2024
1af1c11
fix: change replace to update github outputs
santhitak Mar 27, 2024
c40369d
fix: change typo link to dep_link
santhitak Mar 27, 2024
78fce6e
fix: change deplink to link
santhitak Mar 27, 2024
623ab9e
fix: link value
santhitak Mar 27, 2024
02499c2
feat: use deploymentlink.txt
santhitak Mar 27, 2024
a612872
feat: test txt path
santhitak Mar 27, 2024
7e107a8
test: test txt path
santhitak Mar 27, 2024
10ae327
feat: temp remove comment
santhitak Mar 27, 2024
a7613ca
build(deps): tanstack table
santhitak Mar 28, 2024
b65e0af
feat: status badge
santhitak Mar 28, 2024
87882d1
feat: table
santhitak Mar 28, 2024
5291517
fix: table layout
santhitak Mar 28, 2024
7aee48e
feat: project routes
santhitak Mar 28, 2024
dbca701
feat: main table dashboard
santhitak Mar 28, 2024
84aab8f
feat: credit box
santhitak Mar 28, 2024
5408273
feat: fix colors
santhitak Mar 28, 2024
81ce463
bug: revert workflows
santhitak Mar 28, 2024
ebf4e7c
fix: remove credit unused props
santhitak Mar 28, 2024
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
22 changes: 21 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,24 @@ jobs:
run: pnpm nx affected -t build

- name: Run deploy task
run: pnpm nx affected -t deploy
run: |
pnpm nx affected -t deploy > ./scripts/deployment.log
chmod +x ./scripts/deploy_link.sh
./scripts/deploy_link.sh

- name: Get deployment link
id: deploy_link
run: echo "dep_link=$(cat deployment_link.txt)" >> "$GITHUB_OUTPUT"

- name: Publish deployment link
uses: actions/github-script@v4
with:
# script: |
# const issueNumber = '${{ github.event.number }}'
# github.issues.createComment({
# owner: context.repo.owner,
# repo: context.repo.repo,
# issue_number: issueNumber,
# body: `### QA Deployment
# result: ${{ steps.deploy_link.outputs.dep_link }}`
# });
42 changes: 42 additions & 0 deletions apps/web/src/routes/dashboard/components/credit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Component, component$ } from '@builder.io/qwik';
import { Box, Button, Text } from '@producktivity/ui';
import { LuCar } from '@qwikest/icons/lucide';

const MockCredit: CreditProps = {
totalCredit: 20,
latestUpdate: new Date('03-14-2024'),
};

export interface CreditProps {
totalCredit: number;
latestUpdate: Date;
}
export const Credit: Component<CreditProps> = component$(() => {
return (
<Box width="full" variant="surface" rounded="md">
<Box width="full" padding="2" gap="2" align="between-center">
<Text variant="h2" weight="bold">
Available Credit(s)
</Text>
<Text variant="title" weight="semibold">
{MockCredit.totalCredit}
</Text>
<Box width="full" direction="horizontal" align="between-center">
<Text theme="secondary" variant="small">
Last Topup: {MockCredit.latestUpdate.toLocaleDateString()}
</Text>
<Button rounded="full" variant="badge-tertiary">
<Box width="full" direction="horizontal" gap="0.5">
<Text variant="small" theme="tertiary">
<LuCar />
</Text>
<Text variant="small" theme="tertiary">
Top Up
</Text>
</Box>
</Button>
</Box>
</Box>
</Box>
);
});
126 changes: 123 additions & 3 deletions apps/web/src/routes/dashboard/components/dashboard-tab.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,130 @@
import { component$ } from '@builder.io/qwik';
import { Box } from '@producktivity/ui';
import { Box, Text } from '@producktivity/ui';
import { Credit } from './credit';
import { DashboardTable } from './dashboard-table';

export interface TaskMemberProps {
name: string;
}

export type TaskStatus = 'in progress' | 'failed' | 'success';

export interface TaskProps {
id: number;
title: string;
status: TaskStatus;
member: TaskMemberProps[];
createdWhen: Date;
finishedWhen?: Date;
}

const MockDashboardTasks: TaskProps[] = [
{
id: 0,
title: 'KMITL Volunteering',
status: 'failed',
createdWhen: new Date('02-11-2024'),
member: [
{
name: 'Boonpongkrong Narongrich',
},
],
finishedWhen: new Date('02-11-2024'),
},
{
id: 0,
title: 'KMITL Adhoc Staff',
status: 'failed',
createdWhen: new Date('02-17-2024'),
member: [
{
name: 'Sainan Anannarongdech',
},
],
finishedWhen: new Date('11-02-2024'),
},
{
id: 2,
title: 'IT Open house participants',
status: 'success',
createdWhen: new Date('03-21-2024'),
member: [
{
name: 'Rafah Pipatpong',
},
{
name: 'Sainan Anannarongdech',
},
{
name: 'Boonpradab Narongrich',
},
],
finishedWhen: new Date('03-21-2024'),
},
{
id: 3,
title: 'Tobe IT Bootcamp',
status: 'in progress',
createdWhen: new Date(),
member: [
{
name: 'Thitipat Pipatpong',
},
{
name: 'Boonnarong Kiatnakin',
},
],
},
{
id: 4,
title: 'Tobe IT Staff',
status: 'in progress',
createdWhen: new Date(),
member: [
{
name: 'Boonnarong Kiatnakin',
},
],
},
];

export const DashboardTab = component$(() => {
return (
<Box width="full">
<Box padding="2">dashboard tab</Box>
<Box paddingX="4" direction="horizontal" width="full" align="top">
<Box paddingX="4" paddingY="2" width="3/4" variant="surface" rounded="md">
<Box direction="horizontal" width="full" align="between-center">
<Box>
<Text variant="title" weight="bold">
Last Tasks
</Text>
<Text theme="secondary">{MockDashboardTasks ? MockDashboardTasks.length : 0} Total</Text>
</Box>
<Box direction="horizontal" gap="1">
<Box align="center">
<Text variant="title" weight="medium" theme="primary">
{MockDashboardTasks.filter((task) => task.status === 'success').length}
</Text>
<Text theme="primary">Done</Text>
</Box>
<Box align="center">
<Text variant="title" weight="medium" theme="secondary">
{MockDashboardTasks.filter((task) => task.status === 'in progress').length}
</Text>
<Text theme="secondary">In Progress</Text>
</Box>
<Box align="center">
<Text variant="title" weight="medium" theme="error">
{MockDashboardTasks.filter((task) => task.status === 'failed').length}
</Text>
<Text theme="error">Failed</Text>
</Box>
</Box>
</Box>
<DashboardTable data={MockDashboardTasks} />
</Box>
<Box paddingX="4" width="quarter">
<Credit />
</Box>
</Box>
);
});
95 changes: 95 additions & 0 deletions apps/web/src/routes/dashboard/components/dashboard-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { Component, component$ } from '@builder.io/qwik';
import { createColumnHelper, getCoreRowModel, flexRender, useQwikTable } from '@tanstack/qwik-table';
import { TaskMemberProps, TaskProps, TaskStatus } from './dashboard-tab';
import { Box, Button } from '@producktivity/ui';
import { Link } from '@builder.io/qwik-city';

const columnHelper = createColumnHelper<TaskProps>();

function getTaskDetail(row: string) {
return (
<Link style={{ color: '#3040c9', textDecoration: 'underline' }} href={`/dashboard/project/${row.split(' ').join('-').toLowerCase()}`}>
{row}
</Link>
);
}

function getTaskMember(row: TaskMemberProps[]) {
return <p>{row.length}</p>;
}

function getTaskStatus(row: TaskStatus) {
return (
<Button rounded="md" variant={row === 'success' ? 'badge-success' : row === 'failed' ? 'badge-error' : 'badge-info'}>
{row}
</Button>
);
}

const columns = [
columnHelper.accessor('title', {
header: () => 'Project',
cell: (info) => getTaskDetail(info.getValue()),
}),
columnHelper.accessor('member', {
header: () => 'Member',
cell: (info) => getTaskMember(info.getValue()),
sortingFn: 'alphanumeric',
}),
columnHelper.accessor('status', {
header: () => 'Status',
cell: (info) => getTaskStatus(info.getValue()),
}),
columnHelper.accessor('createdWhen', {
header: () => 'Task Created',
cell: (info) => info.getValue().toLocaleString(),
sortingFn: 'datetime',
}),
columnHelper.accessor('finishedWhen', {
header: () => 'Task Finished',
cell: (info) => (info.getValue() ? info.getValue()?.toLocaleString() : 'not finished'),
sortingFn: 'datetime',
}),
];

interface DashboardTableProps {
data: TaskProps[];
}

export const DashboardTable: Component<DashboardTableProps> = component$(({ data }: DashboardTableProps) => {
const table = useQwikTable({
columns,
data: data,
getCoreRowModel: getCoreRowModel(),
enableSorting: true,
});

return (
<Box width="full" paddingTop="2" paddingLeft="3">
<table class="w-full table-fixed text-sm text-left text-gray-500 dark:text-gray-400">
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th key={header.id} scope="col">
<Box align="between-start">{flexRender(header.column.columnDef.header, header.getContext())}</Box>
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id} class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
{row.getVisibleCells().map((cell) => (
<td key={cell.id} class="py-2">
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
</Box>
);
});
16 changes: 16 additions & 0 deletions apps/web/src/routes/dashboard/components/plan-badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { component$ } from '@builder.io/qwik';
import { Button } from '@producktivity/ui';

type PlanType = 'Professional' | 'Enterprise' | 'Hobby';

interface PlanBadgeProps {
planType: PlanType;
}

export const PlanBadge = component$((badge: PlanBadgeProps) => {
return (
<Button rounded="full" variant={badge.planType === 'Professional' ? 'badge-primary' : badge.planType === 'Enterprise' ? 'badge-tertiary' : 'badge-secondary'}>
{badge.planType}
</Button>
);
});
21 changes: 18 additions & 3 deletions apps/web/src/routes/dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { component$, useSignal } from '@builder.io/qwik';
import { DocumentHead } from '@builder.io/qwik-city';
import { Box, Button, Text } from '@producktivity/ui';
import { generateSeoConfig } from '../../configs/seo';
import { LuPlusCircle } from '@qwikest/icons/lucide';
import { LuArrowUpCircle, LuPlusCircle } from '@qwikest/icons/lucide';
import { DashboardTab } from './components/dashboard-tab';
import { TemplateTab } from './components/template-tab';
import { ProjectTab } from './components/project-tab';
import { PlanBadge } from './components/plan-badge';

interface DashboardTabsProps {
id: number;
Expand All @@ -23,7 +24,7 @@ export default component$(() => {

return (
<Box height="full-screen" width="full-screen" align="top-left">
<Box padding="4" width="full" direction="horizontal" align="between-center">
<Box paddingY="2" paddingX="4" width="full" direction="horizontal" align="between-center">
<Box direction="horizontal" gap="1">
{dashboardTabs.map((item: DashboardTabsProps) => (
<Button rounded="full" variant={item.id === currentActiveTabId.value ? 'primary' : 'secondary'} key={item.id} onClick$={() => (currentActiveTabId.value = item.id)}>
Expand All @@ -40,7 +41,21 @@ export default component$(() => {
</Box>
</Button>
</Box>
<Box paddingX="4">
<Box direction="horizontal" gap="0.5" paddingX="4">
<Text>Current Plan</Text>
<PlanBadge planType="Professional" />
<Button rounded="full" href="/pricing">
<Box direction="horizontal" align="center" gap="0.5">
<Text theme="surface">
<LuArrowUpCircle />
</Text>
<Text theme="surface" variant="small">
Upgrade
</Text>
</Box>
</Button>
</Box>
<Box marginY="2" width="full">
{currentActiveTabId.value === 0 && <DashboardTab />}
{currentActiveTabId.value === 1 && <ProjectTab />}
{currentActiveTabId.value === 2 && <TemplateTab />}
Expand Down
18 changes: 18 additions & 0 deletions apps/web/src/routes/dashboard/project/[id]/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { component$ } from '@builder.io/qwik';
import { DocumentHead, useLocation } from '@builder.io/qwik-city';
import { Box, Text } from '@producktivity/ui';
import { generateSeoConfig } from '../../../../configs/seo';

export default component$(() => {
const location = useLocation();

return (
<Box id={location.params.id}>
<Text variant="title" weight="bold">
Projects
</Text>
</Box>
);
});

export const head: DocumentHead = generateSeoConfig({ title: 'Projects' });
16 changes: 16 additions & 0 deletions apps/web/src/routes/dashboard/project/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { component$ } from '@builder.io/qwik';
import { DocumentHead } from '@builder.io/qwik-city';
import { Text } from '@producktivity/ui';
import { generateSeoConfig } from '../../../configs/seo';

export default component$(() => {
return (
<>
<Text variant="title" weight="bold">
Projects
</Text>
</>
);
});

export const head: DocumentHead = generateSeoConfig({ title: 'Projects' });
Loading