Skip to content

Commit

Permalink
A4A > Referrals: Implement agency client subscriptions list view (#91334
Browse files Browse the repository at this point in the history
)

* Implement Client UI

* Address PR comments

* Implement A4A client subscriptions list
  • Loading branch information
yashwin authored and pull[bot] committed Jun 14, 2024
1 parent e339d25 commit 5335066
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 4 deletions.
3 changes: 2 additions & 1 deletion client/a8c-for-agencies/sections/client/controller.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ClientSidebar from '../../components/sidebar-menu/client';
import PaymentMethodAdd from '../purchases/payment-methods/payment-method-add';
import PaymentMethodOverview from '../purchases/payment-methods/payment-method-overview';
import ClientLanding from './client-landing';
import SubscriptionsList from './primary/subscriptions-list';

export const clientContext: Callback = ( context, next ) => {
context.secondary = <ClientSidebar path={ context.path } />;
Expand All @@ -18,7 +19,7 @@ export const clientLandingContext: Callback = ( context, next ) => {
};

export const clientSubscriptionsContext: Callback = ( context, next ) => {
context.primary = <div>Subscriptions</div>;
context.primary = <SubscriptionsList />;
context.secondary = <ClientSidebar path={ context.path } />;
next();
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useQuery } from '@tanstack/react-query';
import wpcom from 'calypso/lib/wp';
import { SubscriptionAPIResponse, Subscription } from '../types';

const getClientSubscriptions = ( subscriptions: SubscriptionAPIResponse[] ) => {
const products: Subscription[] = subscriptions.reduce( ( acc: Subscription[], curr ) => {
curr.products.forEach( ( product ) => {
acc.push( {
...product,
status: curr.status,
referral_id: curr.id,
// id is a combination of referral_id and product_id because none of them are unique
id: parseInt( `${ curr.id }${ product.product_id }` ),
} );
} );
return acc;
}, [] );
return products;
};

export default function useFetchClientSubscriptions() {
const data = useQuery( {
queryKey: [ 'a4a-client-subscriptions' ],
queryFn: () =>
wpcom.req.get( {
apiNamespace: 'wpcom/v2',
path: '/agency-client/referrals',
} ),
refetchOnWindowFocus: false,
select: getClientSubscriptions,
} );

return data;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export const getSubscriptionStatus = (
status: string,
translate: ( key: string ) => string
): {
children: string | undefined;
type: 'success' | 'warning' | undefined;
} => {
switch ( status ) {
case 'active':
return {
children: translate( 'Active' ),
type: 'success',
};
case 'pending':
return {
children: translate( 'Pending' ),
type: 'warning',
};
case 'overdue':
return {
children: translate( 'Overdue' ),
type: 'warning',
};
default:
return {
children: undefined,
type: undefined,
};
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { Button } from '@automattic/components';
import { useTranslate } from 'i18n-calypso';
import { useMemo, ReactNode, useState } from 'react';
import { initialDataViewsState } from 'calypso/a8c-for-agencies/components/items-dashboard/constants';
import ItemsDataViews from 'calypso/a8c-for-agencies/components/items-dashboard/items-dataviews';
import Layout from 'calypso/a8c-for-agencies/components/layout';
import LayoutBody from 'calypso/a8c-for-agencies/components/layout/body';
import LayoutHeader, {
LayoutHeaderTitle as Title,
} from 'calypso/a8c-for-agencies/components/layout/header';
import LayoutTop from 'calypso/a8c-for-agencies/components/layout/top';
import MobileSidebarNavigation from 'calypso/a8c-for-agencies/components/sidebar/mobile-sidebar-navigation';
import TextPlaceholder from 'calypso/a8c-for-agencies/components/text-placeholder';
import useProductsQuery from 'calypso/a8c-for-agencies/data/marketplace/use-products-query';
import StatusBadge from 'calypso/a8c-for-agencies/sections/referrals/common/step-section-item/status-badge';
import useFetchClientSubscriptions from '../../hooks/use-fetch-client-subscriptions';
import { getSubscriptionStatus } from '../../lib/get-subscription-status';
import type { Subscription } from '../../types';

import './style.scss';

export default function SubscriptionsList() {
const translate = useTranslate();
const [ dataViewsState, setDataViewsState ] = useState( initialDataViewsState );

const { data, isFetching } = useFetchClientSubscriptions();
const { data: products, isFetching: isFetchingProducts } = useProductsQuery( true );

const title = translate( 'Your subscriptions' );

const fields = useMemo(
() => [
{
id: 'purchase',
header: translate( 'Purchase' ).toUpperCase(),
getValue: () => '-',
render: ( { item }: { item: Subscription } ): ReactNode => {
const product = products?.find( ( product ) => product.product_id === item.product_id );
return isFetchingProducts ? <TextPlaceholder /> : product?.name;
},
enableHiding: false,
enableSorting: false,
},
{
id: 'price',
header: translate( 'Price' ).toUpperCase(),
getValue: () => '-',
render: ( { item }: { item: Subscription } ): ReactNode => {
const product = products?.find( ( product ) => product.product_id === item.product_id );
return isFetchingProducts ? <TextPlaceholder /> : `$${ product?.amount }`;
},
enableHiding: false,
enableSorting: false,
},
{
id: 'subscription-status',
header: translate( 'Subscription Status' ).toUpperCase(),
getValue: () => '-',
render: ( { item }: { item: Subscription } ): ReactNode => {
const { children, type } = getSubscriptionStatus( item.status, translate );
return children ? <StatusBadge statusProps={ { children, type } } /> : '-';
},
enableHiding: false,
enableSorting: false,
},
{
id: 'actions',
header: translate( 'Actions' ).toUpperCase(),
getValue: () => '-',
render: ( { item }: { item: Subscription } ): ReactNode => {
const status = item.status;
const isActive = status === 'active';
return isActive ? (
<Button compact>{ translate( 'Cancel the subscription' ) }</Button>
) : (
'-'
);
},
enableHiding: false,
enableSorting: false,
},
],
[ isFetchingProducts, products, translate ]
);

return (
<Layout
className="subscriptions-list__layout"
title={ title }
wide
sidebarNavigation={ <MobileSidebarNavigation /> }
withBorder
>
<LayoutTop>
<LayoutHeader>
<Title>{ title } </Title>
</LayoutHeader>
</LayoutTop>

<LayoutBody>
<div className="redesigned-a8c-table">
<ItemsDataViews
data={ {
items: data || [],
pagination: {
totalItems: 1,
totalPages: 1,
},
itemFieldId: 'id',
enableSearch: false,
fields: fields,
actions: [],
setDataViewsState: setDataViewsState,
dataViewsState: dataViewsState,
} }
isLoading={ isFetching }
/>
</div>
</LayoutBody>
</Layout>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.subscriptions-list__layout {
&.main.a4a-layout.is-with-border .a4a-layout__top-wrapper:not(.has-navigation) {
padding-block-start: 24px;
padding-block-end: 0;
}
}
20 changes: 20 additions & 0 deletions client/a8c-for-agencies/sections/client/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
interface Product {
date_assigned: string;
license_id: number;
license_key: string;
product_id: number;
quantity: number;
site_assigned: string;
}

export interface SubscriptionAPIResponse {
id: number;
products: Product[];
status: string;
}

export interface Subscription extends Product {
id: number;
status: string;
referral_id: number;
}
14 changes: 11 additions & 3 deletions client/a8c-for-agencies/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -547,9 +547,17 @@ html {
color: var(--color-accent-80);
}

.dataviews-view-table tr td:first-child,
.dataviews-view-table tr th:first-child {
padding-inline-start: 16px;
.dataviews-view-table tr {
td,
th {
&:first-child {
padding-inline-start: 16px;
}
&:last-child {
text-align: right;
padding-inline-end: 16px;
}
}
}

.dataviews-view-list li {
Expand Down

0 comments on commit 5335066

Please sign in to comment.