Skip to content

Commit

Permalink
B 2730 create rewards side panel (#633)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexbeno authored Nov 15, 2024
1 parent c5d455a commit 2ee104a
Show file tree
Hide file tree
Showing 39 changed files with 786 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ export function useFilterColumns() {
cell: info => {
const project = info.getValue();

return <CellProjects projects={project ? [project] : []} singleProps={{ shape: "squared" }} />;
return (
<CellProjects projects={project ? [project] : []} singleProps={{ shape: "squared", withPopover: false }} />
);
},
}),
from: columnHelper.accessor("from", {
Expand All @@ -101,7 +103,12 @@ export function useFilterColumns() {
cell: info => {
const from = info.getValue();

return <CellAvatar avatars={from ? [{ src: from.avatarUrl, name: from.login }] : []} />;
return (
<CellAvatar
avatars={from ? [{ src: from.avatarUrl, name: from.login }] : []}
singleProps={{ withPopover: false }}
/>
);
},
}),
contributions: columnHelper.accessor("items", {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Button } from "@/design-system/atoms/button/variants/button-default";

import { useFilterData } from "@/shared/features/filters/_contexts/filter-data/filter-data.context";
import { ContributorProjectFilter } from "@/shared/features/filters/contributor-project-filter/contributor-project-filter";
import { CurrencyFilter } from "@/shared/features/filters/currency-filter/currency-filter";
import { ProjectFilter } from "@/shared/features/filters/project-filter/project-filter";
import { SidePanelBody } from "@/shared/features/side-panels/side-panel-body/side-panel-body";
import { SidePanelFooter } from "@/shared/features/side-panels/side-panel-footer/side-panel-footer";
import { SidePanelHeader } from "@/shared/features/side-panels/side-panel-header/side-panel-header";
Expand All @@ -27,11 +27,10 @@ export function FilterData() {
canClose={true}
/>
<SidePanelBody>
<ContributorProjectFilter
selectedUser={filters.contributors?.map(String)}
onSelect={(users: string[]) => {
setFilters({ contributors: users.map(Number) });
}}
<ProjectFilter
selectedProjects={filters.projectIds}
onSelect={projectIds => setFilters({ projectIds })}
mine={false}
/>
<CurrencyFilter selectedCurrencies={filters.currencies} onSelect={currencies => setFilters({ currencies })} />
</SidePanelBody>
Expand Down
17 changes: 7 additions & 10 deletions app/my-dashboard/_features/rewards-table/rewards-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import { useMemo, useState } from "react";

import { RewardReactQueryAdapter } from "@/core/application/react-query-adapter/reward";
import { GetProjectRewardsPortParams, GetRewardsQueryParams } from "@/core/domain/reward/reward-contract.types";
import { GetRewardsPortParams, GetRewardsQueryParams } from "@/core/domain/reward/reward-contract.types";

import { Typo } from "@/design-system/atoms/typo";
import { Table, TableLoading } from "@/design-system/molecules/table";
Expand All @@ -15,22 +15,20 @@ import { TABLE_DEFAULT_COLUMN } from "@/shared/constants/table";
import { FilterButton } from "@/shared/features/filters/_components/filter-button/filter-button";
import { FilterDataProvider } from "@/shared/features/filters/_contexts/filter-data/filter-data.context";
import { useAuthUser } from "@/shared/hooks/auth/use-auth-user";
import { useRewardDetailSidepanel } from "@/shared/panels/reward-detail-sidepanel/reward-detail-sidepanel.hooks";

import { FilterColumns } from "./_components/filter-columns/filter-columns";
import { useFilterColumns } from "./_components/filter-columns/filter-columns.hooks";
import { FilterData } from "./_components/filter-data/filter-data";
import { useProjectRewardsFilterDataSidePanel } from "./_components/filter-data/filter-data.hooks";

export type RewardsTableFilters = Omit<
NonNullable<GetProjectRewardsPortParams["queryParams"]>,
"pageSize" | "pageIndex"
>;
export type RewardsTableFilters = Omit<NonNullable<GetRewardsPortParams["queryParams"]>, "pageSize" | "pageIndex">;

export function RewardsTable() {
const [search, setSearch] = useState<string>();
const [debouncedSearch, setDebouncedSearch] = useState<string>();
const { open: openFilterPanel } = useProjectRewardsFilterDataSidePanel();
// const { open } = useRewardDetailSidepanel();
const { open } = useRewardDetailSidepanel();
const [filters, setFilters] = useState<RewardsTableFilters>({});
const { githubUserId } = useAuthUser();

Expand Down Expand Up @@ -97,10 +95,9 @@ export function RewardsTable() {
headerGroups: table.getHeaderGroups(),
}}
rows={table.getRowModel().rows}
// TODO @Mehdi enable reward detail sidepanel once feature ready
// onRowClick={row => {
// open({ rewardId: row.original.id, projectId: projectData?.id ?? "" });
// }}
onRowClick={row => {
open({ rewardId: row.original.id });
}}
/>
{hasNextPage ? <ShowMore onNext={fetchNextPage} loading={isFetchingNextPage} /> : null}
</ScrollView>
Expand Down
2 changes: 2 additions & 0 deletions app/my-dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { PageWrapper } from "@/shared/features/page-wrapper/page-wrapper";
import { RequestPaymentFlowProvider } from "@/shared/panels/_flows/request-payment-flow/request-payment-flow.context";
import { ContributionsSidepanel } from "@/shared/panels/contribution-sidepanel/contributions-sidepanel";
import { ContributorSidepanel } from "@/shared/panels/contributor-sidepanel/contributor-sidepanel";
import { RewardDetailSidepanel } from "@/shared/panels/reward-detail-sidepanel/reward-detail-sidepanel";
import { PosthogCaptureOnMount } from "@/shared/tracking/posthog/posthog-capture-on-mount/posthog-capture-on-mount";
import { Translate } from "@/shared/translation/components/translate/translate";

Expand Down Expand Up @@ -45,6 +46,7 @@ function MyDashboardPage() {

<ContributorSidepanel />
<ContributionsSidepanel />
<RewardDetailSidepanel />
</RequestPaymentFlowProvider>
</PageWrapper>
);
Expand Down
3 changes: 1 addition & 2 deletions core/application/react-query-adapter/reward/client/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
export * from "./use-get-project-rewards";
export * from "./use-get-project-reward";
export * from "./use-get-project-reward-items";
export * from "./use-create-rewards";
export * from "./use-add-other-work";
export * from "./use-add-other-pull-request";
export * from "./use-add-other-issue";
export * from "./use-cancel-project-reward";
export * from "./use-get-rewards";
export * from "./use-get-reward-by-id";

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import {
} from "@/core/application/react-query-adapter/helpers/use-query-adapter";
import { bootstrap } from "@/core/bootstrap";
import { RewardFacadePort } from "@/core/domain/reward/input/reward-facade-port";
import { RewardInterface } from "@/core/domain/reward/models/reward-model";
import { RewardListItemV2Interface } from "@/core/domain/reward/models/reward-list-item-v2-model";

export function useGetProjectReward({
export function useGetRewardId({
options,
pathParams,
}: UseQueryFacadeParams<RewardFacadePort["getProjectReward"], RewardInterface>) {
}: UseQueryFacadeParams<RewardFacadePort["getRewardById"], RewardListItemV2Interface>) {
const rewardStoragePort = bootstrap.getRewardStoragePortForClient();

return useQuery(
useQueryAdapter({
...rewardStoragePort.getProjectReward({ pathParams }),
...rewardStoragePort.getRewardById({ pathParams }),
options,
})
);
Expand Down
3 changes: 3 additions & 0 deletions core/domain/reward/input/reward-facade-port.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@ import {
GetProjectRewardPortResponse,
GetProjectRewardsPortParams,
GetProjectRewardsPortResponse,
GetRewardByIdPortParams,
GetRewardByIdPortResponse,
GetRewardsPortParams,
GetRewardsPortResponse,
} from "@/core/domain/reward/reward-contract.types";

export interface RewardFacadePort {
getRewards(p: GetRewardsPortParams): GetRewardsPortResponse;
getRewardById(p: GetRewardByIdPortParams): GetRewardByIdPortResponse;
getProjectRewards(p: GetProjectRewardsPortParams): GetProjectRewardsPortResponse;
getProjectReward(p: GetProjectRewardPortParams): GetProjectRewardPortResponse;
getProjectRewardItems(p: GetProjectRewardItemsPortParams): GetProjectRewardItemsPortResponse;
Expand Down
8 changes: 7 additions & 1 deletion core/domain/reward/models/reward-list-item-v2-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { components } from "@/core/infrastructure/marketplace-api-client-adapter

export type RewardListItemResponseV2 = components["schemas"]["RewardPageItemResponse"];

export interface RewardListItemV2Interface extends RewardListItemResponseV2 {}
export interface RewardListItemV2Interface extends RewardListItemResponseV2 {
isBlocked(): boolean;
}

export class RewardListItemV2 implements RewardListItemV2Interface {
id!: RewardListItemResponseV2["id"];
Expand All @@ -19,4 +21,8 @@ export class RewardListItemV2 implements RewardListItemV2Interface {
constructor(props: RewardListItemResponseV2) {
Object.assign(this, props);
}

isBlocked() {
return this.status !== "PENDING_REQUEST" && this.status !== "PROCESSING" && this.status !== "COMPLETE";
}
}
3 changes: 3 additions & 0 deletions core/domain/reward/outputs/reward-storage-port.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ import {
GetProjectRewardPortResponse,
GetProjectRewardsPortParams,
GetProjectRewardsPortResponse,
GetRewardByIdPortParams,
GetRewardByIdPortResponse,
GetRewardsPortParams,
GetRewardsPortResponse,
} from "@/core/domain/reward/reward-contract.types";

export interface RewardStoragePort {
routes: Record<string, string>;
getRewards(p: GetRewardsPortParams): GetRewardsPortResponse;
getRewardById(p: GetRewardByIdPortParams): GetRewardByIdPortResponse;
getProjectRewards(p: GetProjectRewardsPortParams): GetProjectRewardsPortResponse;
getProjectReward(p: GetProjectRewardPortParams): GetProjectRewardPortResponse;
getProjectRewardItems(p: GetProjectRewardItemsPortParams): GetProjectRewardItemsPortResponse;
Expand Down
10 changes: 5 additions & 5 deletions core/domain/reward/reward-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { TranslateProps } from "@/shared/translation/components/translate/transl
export type PayoutStatus = GetProjectRewardsResponse["rewards"][0]["status"];

export interface PayoutStatusContent {
type: "error" | "warning" | "success";
type: "error" | "warning" | "success" | "info";
label: TranslateProps["token"];
icon: IconPort;
}
Expand Down Expand Up @@ -40,7 +40,7 @@ export const PayoutStatusMapping: Record<PayoutStatus, PayoutStatusContent> = {
PENDING_CONTRIBUTOR: {
icon: { component: Users },
label: "features:payoutStatus.statuses.pendingContributor",
type: "warning",
type: "info",
},
PENDING_BILLING_PROFILE: {
icon: { component: TriangleAlert },
Expand Down Expand Up @@ -75,17 +75,17 @@ export const PayoutStatusMapping: Record<PayoutStatus, PayoutStatusContent> = {
LOCKED: {
icon: { component: Lock },
label: "features:payoutStatus.statuses.locked",
type: "warning",
type: "info",
},
PENDING_REQUEST: {
icon: { component: Hourglass },
label: "features:payoutStatus.statuses.pendingRequest",
type: "warning",
type: "info",
},
PROCESSING: {
icon: { component: Hourglass },
label: "features:payoutStatus.statuses.processing",
type: "warning",
type: "info",
},
COMPLETE: {
icon: { component: Check },
Expand Down
14 changes: 14 additions & 0 deletions core/domain/reward/reward-contract.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,20 @@ export type GetRewardsPortParams = HttpClientParameters<{
QueryParams: GetRewardsQueryParams;
}>;

/* ------------------------------ Get Reward by id ------------------------------ */

export type GetRewardByIdResponse = components["schemas"]["RewardPageItemResponse"];

export type GetRewardByIdModel = RewardListItemV2Interface;

type GetRewardByIdPathParams = operations["getReward"]["parameters"]["path"];

export type GetRewardByIdPortResponse = HttpStorageResponse<GetRewardByIdModel>;

export type GetRewardByIdPortParams = HttpClientParameters<{
PathParams: GetRewardByIdPathParams;
}>;

/* ------------------------------ Get Project Rewards ------------------------------ */

export type GetProjectRewardsResponse = components["schemas"]["RewardsPageResponse"];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
GetProjectRewardItemsResponse,
GetProjectRewardResponse,
GetProjectRewardsResponse,
GetRewardByIdResponse,
GetRewardsResponse,
} from "@/core/domain/reward/reward-contract.types";
import { MarketplaceApiVersion } from "@/core/infrastructure/marketplace-api-client-adapter/config/api-version";
Expand All @@ -27,6 +28,7 @@ export class RewardClientAdapter implements RewardStoragePort {

routes = {
getRewards: "rewards",
getRewardById: "rewards/:rewardId",
getProjectRewards: "projects/:projectId/rewards",
getProjectReward: "projects/:projectId/rewards/:rewardId",
cancelProjectReward: "projects/:projectId/rewards/:rewardId",
Expand Down Expand Up @@ -61,6 +63,28 @@ export class RewardClientAdapter implements RewardStoragePort {
tag,
};
};

getRewardById = ({ pathParams }: FirstParameter<RewardStoragePort["getRewardById"]>) => {
const path = this.routes["getRewardById"];
const method = "GET";
const tag = HttpClient.buildTag({ path, pathParams });
const request = async () => {
const data = await this.client.request<GetRewardByIdResponse>({
path,
method,
tag,
pathParams,
});

return new RewardListItemV2(data);
};

return {
request,
tag,
};
};

getProjectRewards = ({ queryParams, pathParams }: FirstParameter<RewardStoragePort["getProjectRewards"]>) => {
const path = this.routes["getProjectRewards"];
const method = "GET";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { ElementType } from "react";

import { Badge } from "@/design-system/atoms/badge";
import { Typo } from "@/design-system/atoms/typo";

import { cn } from "@/shared/helpers/cn";

import { TimelineItemPort } from "../../timeline-item.types";
import { TimelineItemDefaultVariants } from "./default.variants";

export function TimelineItemDefaultAdapter<C extends ElementType = "div">({
as,
classNames,
htmlProps,
label,
badgeProps = {},
color = "brand",
endContent,
children,
icon,
}: TimelineItemPort<C>) {
const Component = as || "div";
const slots = TimelineItemDefaultVariants();

return (
<Component {...htmlProps} className={cn(slots.base(), classNames?.base)}>
<div className={cn(slots.header(), classNames?.header)}>
<div className={cn(slots.titleContainer(), classNames?.titleContainer)}>
<Badge size={"xs"} color={color} shape={"squared"} {...badgeProps} icon={icon} iconOnly={true} />
{label ? (
<Typo size={"xs"} weight={"medium"} as={"div"}>
{label}
</Typo>
) : null}
</div>
{!!endContent && (
<Typo color={"secondary"} size={"xs"} weight={"regular"} as={"div"}>
{endContent}
</Typo>
)}
</div>
{!!children && (
<div className={cn(slots.contentContainer(), classNames?.contentContainer)}>
<div className={cn(slots.contentInner(), classNames?.contentInner)}>{children}</div>
</div>
)}
</Component>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { tv } from "tailwind-variants";

export const TimelineItemDefaultVariants = tv({
slots: {
base: "flex w-full flex-col",
header: "flex w-full items-center justify-between gap-1",
titleContainer: "flex flex-row items-center justify-start gap-3",
contentContainer: "w-full pl-9 pt-4",
contentInner: "w-full",
},
variants: {},
defaultVariants: {},
});
Loading

0 comments on commit 2ee104a

Please sign in to comment.