2
1
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2023-12-13 21:00:40 +01:00

Simplified offers list screen in AdminX (#19190)

fixes ADM-40

- removed layout switch feature, and made the list layout default
- removed the help link, because it will no longer be necessary on the
list screen
- fixed offers count in the table header
This commit is contained in:
Sodbileg Gansukh 2023-11-30 12:23:48 +08:00 committed by GitHub
parent 49eaee40f2
commit 63774463ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -89,42 +89,6 @@ export const CopyLinkButton: React.FC<{offerCode: string}> = ({offerCode}) => {
return <Tooltip containerClassName='group-hover:opacity-100 opacity-0 flex items-center -mr-1 justify-center leading-none w-5 h-5' content={isCopied ? 'Copied' : 'Copy link'} size='sm'><Button color='clear' hideLabel={true} icon={isCopied ? 'check-circle' : 'hyperlink-circle'} iconColorClass={isCopied ? 'text-green w-[14px] h-[14px]' : 'w-[18px] h-[18px]'} label={isCopied ? 'Copied' : 'Copy'} unstyled={true} onClick={handleCopyClick} /></Tooltip>;
};
const OfferCard: React.FC<{amount: number, cadence: string, currency: string, duration: string, name: string, code: string, offerId: string, offerTier: Tier | undefined, redemptionCount: number, type: OfferType, onClick: ()=>void}> = ({amount, cadence, currency, duration, name, code, offerId, offerTier, redemptionCount, type, onClick}) => {
let tierName = offerTier?.name + ' ' + getOfferCadence(cadence) + ' — ' + getOfferDuration(duration);
const {discountColor, discountOffer, originalPriceWithCurrency, updatedPriceWithCurrency} = getOfferDiscount(type, amount, cadence, currency || 'USD', offerTier);
const isTierArchived = offerTier?.active === false;
return (
<div className={`group relative ${isTierArchived ? '' : 'cursor-pointer'} border border-transparent bg-grey-100 p-5 transition-all ${!isTierArchived ? 'hover:border-grey-100 hover:bg-grey-75 hover:shadow-sm' : ''} dark:bg-grey-950 ${!isTierArchived ? 'dark:hover:border-grey-800' : ''}`} onClick={!isTierArchived ? onClick : () => {}}>
<div className='flex h-full flex-col gap-6'>
<div className={`${isTierArchived ? 'pointer-events-none opacity-50' : ''} flex grow items-baseline justify-between gap-2`}>
<h2 className='text-[1.6rem] font-semibold'>{name}</h2>
<span className={`-translate-y-px whitespace-nowrap text-xs font-semibold uppercase ${discountColor}`}>{discountOffer}</span>
</div>
<div className={`${isTierArchived ? 'pointer-events-none opacity-50' : ''} flex items-baseline gap-1`}>
<span className='text-3xl font-bold tracking-tight'>{updatedPriceWithCurrency}</span>
<span className='text-[1.6rem] font-medium text-grey-700 line-through'>{originalPriceWithCurrency}</span>
</div>
<div className='flex items-center justify-between'>
<div className={`${isTierArchived ? 'pointer-events-none opacity-50' : ''} flex flex-col items-start text-xs`}>
<span className='font-medium'>{tierName}</span>
<a className='text-grey-700 hover:underline' href={createRedemptionFilterUrl(offerId)}>{redemptionCount} redemptions</a>
</div>
{!isTierArchived ?
<CopyLinkButton offerCode={code} /> :
null
}
</div>
</div>
{isTierArchived ?
<div className='absolute left-4 top-4 whitespace-nowrap rounded-sm bg-black px-2 py-0.5 text-xs leading-normal text-white opacity-0 transition-all group-hover:opacity-100 dark:bg-grey-950'>This offer is disabled, because <br /> it is tied to an archived tier.</div> :
null
}
</div>
);
};
export const OffersIndexModal = () => {
const modal = useModal();
const {updateRoute} = useRouting();
@ -149,7 +113,6 @@ export const OffersIndexModal = () => {
{id: 'archived', title: 'Archived'}
];
const [selectedTab, setSelectedTab] = useState('active');
const [selectedLayout, setSelectedLayout] = useState('card');
const [sortOption, setSortOption] = useState('date-added');
const [sortDirection, setSortDirection] = useState('desc');
@ -179,43 +142,11 @@ export const OffersIndexModal = () => {
}
});
const cardLayoutOutput = <div className='mt-8 grid grid-cols-1 gap-6 min-[600px]:grid-cols-2 min-[900px]:grid-cols-3'>
{sortedOffers.filter((offer) => {
const offerTier = allTiers?.find(tier => tier.id === offer?.tier.id);
//Check to filter out offers with archived offerTier
return (selectedTab === 'active' && (offer.status === 'active' && offerTier && offerTier.active === true)) ||
(selectedTab === 'archived' && (offer.status === 'archived' || (offerTier && offerTier.active === false)));
}).map((offer) => {
const offerTier = allTiers?.find(tier => tier.id === offer?.tier.id);
if (!offerTier) {
return null;
}
return (
<OfferCard
key={offer?.id}
amount={offer?.amount}
cadence={offer?.cadence}
code={offer?.code}
currency={offer?.currency || 'USD'}
duration={offer?.duration}
name={offer?.name}
offerId={offer?.id ? offer.id : ''}
offerTier={offerTier}
redemptionCount={offer?.redemption_count ? offer.redemption_count : 0}
type={offer?.type as OfferType}
onClick={() => handleOfferEdit(offer?.id ? offer.id : '')}
/>
);
})}
</div>;
const listLayoutOutput = <div className='overflow-x-auto'>
<table className='m-0 w-full'>
{(selectedTab === 'active' && activeOffers.length > 0) || (selectedTab === 'archived' && archivedOffers.length > 0) ?
<tr className='border-b border-b-grey-300'>
<th className='px-5 py-2.5 pl-0 text-xs font-normal text-grey-700'>{sortedOffers.length} {sortedOffers.length > 1 ? 'offers' : 'offer'}</th>
<th className='px-5 py-2.5 pl-0 text-xs font-normal text-grey-700'>{selectedTab === 'active' ? activeOffers.length : archivedOffers.length} {selectedTab === 'active' ? (activeOffers.length !== 1 ? 'offers' : 'offer') : (archivedOffers.length !== 1 ? 'offers' : 'offer')}</th>
<th className='px-5 py-2.5 text-xs font-normal text-grey-700'>Tier</th>
<th className='px-5 py-2.5 text-xs font-normal text-grey-700'>Terms</th>
<th className='px-5 py-2.5 text-xs font-normal text-grey-700'>Price</th>
@ -264,20 +195,15 @@ export const OffersIndexModal = () => {
}}
animate={false}
cancelLabel=''
footer={
<div className='mx-8 flex w-full items-center justify-between'>
<a className='text-sm' href="https://ghost.org/help/offers" rel="noopener noreferrer" target="_blank"> Learn about offers in Ghost</a>
<Button color='black' label='Close' onClick={() => {
modal.remove();
updateRoute('offers');
}} />
</div>
}
header={false}
height='full'
size='lg'
testId='offers-modal'
stickyFooter
onOk={() => {
modal.remove();
updateRoute('offers');
}}
>
<div className='pt-6'>
<header>
@ -295,7 +221,7 @@ export const OffersIndexModal = () => {
</div>
<div className='mt-12 flex items-center justify-between border-b border-b-grey-300 pb-2.5'>
<h1 className='text-3xl'>{offersTabs.find(tab => tab.id === selectedTab)?.title} offers</h1>
<div className='flex gap-3'>
<div className='-mr-3'>
<SortMenu
direction='desc'
items={[
@ -312,10 +238,6 @@ export const OffersIndexModal = () => {
setSortOption(selectedOption);
}}
/>
<div className='flex gap-3'>
<Button icon='layout-module-1' iconColorClass={selectedLayout === 'card' ? 'text-black' : 'text-grey-500'} link={true} size='sm' onClick={() => setSelectedLayout('card')} />
<Button icon='layout-headline' iconColorClass={selectedLayout === 'list' ? 'text-black' : 'text-grey-500'} link={true} size='sm' onClick={() => setSelectedLayout('list')} />
</div>
</div>
</div>
</header>
@ -331,7 +253,7 @@ export const OffersIndexModal = () => {
</NoValueLabel> :
null
}
{selectedLayout === 'card' ? cardLayoutOutput : listLayoutOutput}
{listLayoutOutput}
</div>
</Modal>;
};