mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 20:03:12 +03:00
Better no offers handling in offers list screen (#19138)
no issues - active/archived tabs are no longer hidden, they're always visible regardless of if there's an offer or not - same for the modal footer, it's always visible - used a simple NoValueLabel component instead of custom no offers view
This commit is contained in:
parent
b9d7c2d3a5
commit
b9de456026
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="-0.75 -0.75 24 24" height="24" width="24"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M8.437481250000001 17.98875c-0.26370937499999997 0.263625 -0.621328125 0.41175 -0.99421875 0.41175 -0.37288125 0 -0.730509375 -0.148125 -0.99421875 -0.41175l-5.042812499999999 -5.041875c-0.13067812499999998 -0.13059375 -0.23433749999999998 -0.28565625 -0.3050625 -0.45628125 -0.070734375 -0.17071875 -0.10713750000000001 -0.35362499999999997 -0.10713750000000001 -0.53840625 0 -0.1846875 0.036403125 -0.3676875 0.10713750000000001 -0.5383125000000001 0.070725 -0.17071875 0.174384375 -0.32578124999999997 0.3050625 -0.45637500000000003L11.25 1.11376875c0.13059375 -0.13055624999999998 0.28575 -0.2341059375 0.45637500000000003 -0.304723125 0.17071875 -0.07061625 0.35362499999999997 -0.10692 0.5383125000000001 -0.106835625h5.041875c0.3729375 0 0.73059375 0.1481578125 0.9943124999999999 0.4118775 0.26371875 0.263728125 0.4119375 0.6214125 0.4119375 0.9943687499999999v5.042812499999999c-0.00009375 0.372703125 -0.148125 0.730125 -0.4115625 0.99375" stroke-width="1.5"></path><path stroke="currentColor" d="M15.1771875 4.56939375c-0.19415625 0 -0.3515625 -0.15739687500000002 -0.3515625 -0.3515625 0 -0.19415625 0.15740625 -0.3515625 0.3515625 -0.3515625" stroke-width="1.5"></path><path stroke="currentColor" d="M15.1771875 4.56939375c0.19415625 0 0.3515625 -0.15739687500000002 0.3515625 -0.3515625 0 -0.19415625 -0.15740625 -0.3515625 -0.3515625 -0.3515625" stroke-width="1.5"></path><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M15.8803125 21.795937499999997c3.10659375 0 5.625 -2.51840625 5.625 -5.625s-2.51840625 -5.625 -5.625 -5.625 -5.625 2.51840625 -5.625 5.625 2.51840625 5.625 5.625 5.625Z" stroke-width="1.5"></path><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="m19.858124999999998 12.193125 -7.95375 7.9546874999999995" stroke-width="1.5"></path></svg>
|
After Width: | Height: | Size: 2.0 KiB |
@ -1,7 +1,7 @@
|
||||
import useFeatureFlag from '../../../../hooks/useFeatureFlag';
|
||||
import {Button, Tab, TabView} from '@tryghost/admin-x-design-system';
|
||||
import {Icon} from '@tryghost/admin-x-design-system';
|
||||
import {Modal} from '@tryghost/admin-x-design-system';
|
||||
import {NoValueLabel} from '@tryghost/admin-x-design-system';
|
||||
import {SortMenu} from '@tryghost/admin-x-design-system';
|
||||
import {Tier, useBrowseTiers} from '@tryghost/admin-x-framework/api/tiers';
|
||||
import {Tooltip} from '@tryghost/admin-x-design-system';
|
||||
@ -111,21 +111,6 @@ const OfferCard: React.FC<{amount: number, cadence: string, currency: string, du
|
||||
);
|
||||
};
|
||||
|
||||
const EmptyScreen: React.FC = () => {
|
||||
const {updateRoute} = useRouting();
|
||||
|
||||
return <div className='flex h-full flex-col items-center justify-center text-center'>
|
||||
<Icon colorClass='text-grey-700' name='ai-tagging-spark' size='xl' />
|
||||
<h1 className='mt-6 text-4xl'>Provide offers to new signups</h1>
|
||||
<div className='max-w-[420px]'>
|
||||
<p className='mt-3 text-[1.6rem]'>Boost your subscriptions by creating targeted discounts to potential members.</p>
|
||||
<div className='mt-8'>
|
||||
<Button color='green' label='Create first offer' fullWidth onClick={() => updateRoute('offers/new')} />
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
};
|
||||
|
||||
export const OffersIndexModal = () => {
|
||||
const modal = useModal();
|
||||
const {updateRoute} = useRouting();
|
||||
@ -217,14 +202,17 @@ export const OffersIndexModal = () => {
|
||||
|
||||
const listLayoutOutput = <div className='overflow-x-auto'>
|
||||
<table className='m-0 w-full'>
|
||||
<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 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>
|
||||
<th className='px-5 py-2.5 text-xs font-normal text-grey-700'>Redemptions</th>
|
||||
<th className='min-w-[80px] px-5 py-2.5 pr-0 text-xs font-normal text-grey-700'></th>
|
||||
</tr>
|
||||
{(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 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>
|
||||
<th className='px-5 py-2.5 text-xs font-normal text-grey-700'>Redemptions</th>
|
||||
<th className='min-w-[80px] px-5 py-2.5 pr-0 text-xs font-normal text-grey-700'></th>
|
||||
</tr> :
|
||||
null
|
||||
}
|
||||
{sortedOffers.filter((offer) => {
|
||||
const offerTier = allTiers?.find(tier => tier.id === offer?.tier.id);
|
||||
//Check to filter out offers with archived offerTier
|
||||
@ -262,15 +250,13 @@ export const OffersIndexModal = () => {
|
||||
animate={false}
|
||||
cancelLabel=''
|
||||
footer={
|
||||
(activeOffers.length > 0 || archivedOffers.length > 0) ?
|
||||
<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> :
|
||||
false
|
||||
<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'
|
||||
@ -278,53 +264,59 @@ export const OffersIndexModal = () => {
|
||||
testId='offers-modal'
|
||||
stickyFooter
|
||||
>
|
||||
{(activeOffers.length > 0 || archivedOffers.length > 0) ?
|
||||
<div className='pt-6'>
|
||||
<header>
|
||||
<div className='flex items-center justify-between'>
|
||||
<div>
|
||||
{activeOffers.length > 0 && archivedOffers.length > 0 ?
|
||||
<TabView
|
||||
border={false}
|
||||
selectedTab={selectedTab}
|
||||
tabs={offersTabs}
|
||||
width='wide'
|
||||
onTabChange={setSelectedTab}
|
||||
/> :
|
||||
null
|
||||
}
|
||||
</div>
|
||||
<Button color='green' icon='add' iconColorClass='green' label='New offer' link={true} size='sm' onClick={() => updateRoute('offers/new')} />
|
||||
<div className='pt-6'>
|
||||
<header>
|
||||
<div className='flex items-center justify-between'>
|
||||
<div>
|
||||
<TabView
|
||||
border={false}
|
||||
selectedTab={selectedTab}
|
||||
tabs={offersTabs}
|
||||
width='wide'
|
||||
onTabChange={setSelectedTab}
|
||||
/>
|
||||
</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>
|
||||
<Button color='green' icon='add' iconColorClass='green' label='New offer' link={true} size='sm' onClick={() => updateRoute('offers/new')} />
|
||||
</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'>
|
||||
<SortMenu
|
||||
direction='desc'
|
||||
items={[
|
||||
{id: 'date-added', label: 'Date added', selected: sortOption === 'date-added'},
|
||||
{id: 'name', label: 'Name', selected: sortOption === 'name'},
|
||||
{id: 'redemptions', label: 'Redemptions', selected: sortOption === 'redemptions'}
|
||||
]}
|
||||
position='right'
|
||||
onDirectionChange={(selectedDirection) => {
|
||||
const newDirection = selectedDirection === 'asc' ? 'desc' : 'asc';
|
||||
setSortDirection(newDirection);
|
||||
}}
|
||||
onSortChange={(selectedOption) => {
|
||||
setSortOption(selectedOption);
|
||||
}}
|
||||
/>
|
||||
<div className='flex gap-3'>
|
||||
<SortMenu
|
||||
direction='desc'
|
||||
items={[
|
||||
{id: 'date-added', label: 'Date added', selected: sortOption === 'date-added'},
|
||||
{id: 'name', label: 'Name', selected: sortOption === 'name'},
|
||||
{id: 'redemptions', label: 'Redemptions', selected: sortOption === 'redemptions'}
|
||||
]}
|
||||
position='right'
|
||||
onDirectionChange={(selectedDirection) => {
|
||||
const newDirection = selectedDirection === 'asc' ? 'desc' : 'asc';
|
||||
setSortDirection(newDirection);
|
||||
}}
|
||||
onSortChange={(selectedOption) => {
|
||||
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>
|
||||
<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>
|
||||
</header>
|
||||
{selectedLayout === 'card' ? cardLayoutOutput : listLayoutOutput}
|
||||
</div> :
|
||||
<EmptyScreen />
|
||||
}
|
||||
</div>
|
||||
</header>
|
||||
{selectedTab === 'active' && activeOffers.length === 0 ?
|
||||
<NoValueLabel icon='tags-block'>
|
||||
No offers found.
|
||||
</NoValueLabel> :
|
||||
null
|
||||
}
|
||||
{selectedTab === 'archived' && archivedOffers.length === 0 ?
|
||||
<NoValueLabel icon='tags-block'>
|
||||
No offers found.
|
||||
</NoValueLabel> :
|
||||
null
|
||||
}
|
||||
{selectedLayout === 'card' ? cardLayoutOutput : listLayoutOutput}
|
||||
</div>
|
||||
</Modal>;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user