Skip to content
This repository has been archived by the owner on Sep 24, 2024. It is now read-only.

Commit

Permalink
chore: show promo rules on detail page
Browse files Browse the repository at this point in the history
  • Loading branch information
marcomontalbano committed Jan 15, 2024
1 parent 19d3daf commit 30e1d52
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 115 deletions.
2 changes: 1 addition & 1 deletion packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"prepare": "touch ./public/config.local.js"
},
"dependencies": {
"@commercelayer/app-elements": "^1.10.1",
"@commercelayer/app-elements": "^1.11.0",
"@commercelayer/sdk": "5.18.0",
"@hookform/resolvers": "^3.3.2",
"lodash": "^4.17.21",
Expand Down
52 changes: 48 additions & 4 deletions packages/app/src/data/ruleBuilder/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,60 @@ import {
} from '@commercelayer/app-elements'
import type { CustomPromotionRule } from '@commercelayer/sdk'
import type { ListableResourceType } from '@commercelayer/sdk/lib/cjs/api'
import { useEffect, useState } from 'react'
import { currencies, type CurrencyCode } from './currencies'

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function usePromotionRules(promotion: Promotion) {
const { sdkClient } = useCoreSdkProvider()
const [output, setOutput] = useState<{
isLoading: boolean
data: ReturnType<typeof toFormLabels>
}>({ isLoading: true, data: null })
useEffect(() => {
promotion.promotion_rules?.forEach((promotionRule) => {
const formLabels = toFormLabels(promotionRule)

const data =
formLabels?.flatMap(async (formLabel) => {
if (formLabel.rel == null) {
return formLabel
}

const promise = sdkClient[formLabel.rel]
.list({
filters: { id_in: formLabel.value.split(',').join(',') }
})
.then((data) => data.map((d) => d.name))
.then((values) => ({
...formLabel,
value: values.join(',')
}))

return await promise
}) ?? []

void Promise.all(data).then((data) => {
setOutput({
isLoading: false,
data
})
})
})
}, [promotion])

return output
}

export function toFormLabels(promotionRule: PromotionRule): Array<{
promotionRule: PromotionRule
valid: boolean
predicate: string
parameter: keyof typeof ruleBuilderConfig
rel?: Extract<ListableResourceType, 'markets' | 'tags'>
operator?: string
value: string
}> | null {
if (promotionRule.type !== 'custom_promotion_rules') {
return null
}

switch (promotionRule.type) {
case 'custom_promotion_rules':
return Object.entries(promotionRule.filters ?? {}).map(
Expand All @@ -38,6 +78,7 @@ export function toFormLabels(promotionRule: PromotionRule): Array<{
const parameter = predicate.replace(regexp, '')
const valid = ruleBuilderConfig[parameter] != null
return {
promotionRule,
valid,
predicate,
rel: ruleBuilderConfig[parameter]?.rel,
Expand All @@ -48,6 +89,9 @@ export function toFormLabels(promotionRule: PromotionRule): Array<{
}
}
)

default:
return null
}
}

Expand Down
17 changes: 13 additions & 4 deletions packages/app/src/pages/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import { Link } from 'wouter'
function HomePage(): JSX.Element {
const {
dashboardUrl,
settings: { mode }
settings: { mode },
canUser
} = useTokenProvider()

return (
Expand All @@ -34,9 +35,17 @@ function HomePage(): JSX.Element {
<List
title='Browse'
actionButton={
<Link href={appRoutes.newSelectType.makePath({})}>
<a>New promo</a>
</Link>
canUser('create', 'buy_x_pay_y_promotions') ||
canUser('create', 'external_promotions') ||
canUser('create', 'fixed_amount_promotions') ||
canUser('create', 'fixed_price_promotions') ||
canUser('create', 'free_gift_promotions') ||
canUser('create', 'free_shipping_promotions') ||
canUser('create', 'percentage_discount_promotions') ? (
<Link href={appRoutes.newSelectType.makePath({})}>
<a>New promo</a>
</Link>
) : undefined
}
>
<Link href={appRoutes.list.makePath({})}>
Expand Down
118 changes: 27 additions & 91 deletions packages/app/src/pages/PromotionConditionsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { type PromotionRule } from '#data/dictionaries/promotion'
import { appRoutes } from '#data/routes'
import { toFormLabels } from '#data/ruleBuilder/config'
import { usePromotionRules, type toFormLabels } from '#data/ruleBuilder/config'
import { usePromotion } from '#hooks/usePromotion'
import {
Card,
Expand All @@ -9,13 +8,11 @@ import {
RemoveButton,
SkeletonTemplate,
Spacer,
useCoreApi,
useCoreSdkProvider,
useTokenProvider
} from '@commercelayer/app-elements'
import type { CustomPromotionRule } from '@commercelayer/sdk'
import type { ListableResourceType } from '@commercelayer/sdk/lib/cjs/api'
import { useCallback, useMemo, useState } from 'react'
import { useCallback, useState } from 'react'
import { Link, useLocation, type RouteComponentProps } from 'wouter'

function Page(
Expand All @@ -26,9 +23,10 @@ function Page(
} = useTokenProvider()
const [, setLocation] = useLocation()

const { isLoading, promotion, mutatePromotion } = usePromotion(
props.params.promotionId
)
const { promotion, mutatePromotion } = usePromotion(props.params.promotionId)

const { isLoading: isLoadingRules, data: rules } =
usePromotionRules(promotion)

return (
<PageLayout
Expand All @@ -48,20 +46,28 @@ function Page(
}
}}
>
<SkeletonTemplate isLoading={isLoading}>
<SkeletonTemplate isLoading={isLoadingRules}>
<Spacer top='10'>
{promotion.promotion_rules?.map((promotionRule) => (
<div key={promotionRule.id}>
<PromotionRuleDetail
onRemove={() => {
setTimeout(() => {
void mutatePromotion()
}, 1000)
}}
promotionRule={promotionRule}
/>
</div>
))}
{rules?.map((formLabel) => {
if (formLabel.promotionRule.type === 'custom_promotion_rules') {
return (
<div key={formLabel.predicate}>
<CustomPromotionRuleItem
key={formLabel.predicate}
onRemove={() => {
setTimeout(() => {
void mutatePromotion()
}, 1000)
}}
customPromotionRule={formLabel.promotionRule}
formLabel={formLabel}
/>
</div>
)
}

return null
})}
<Spacer top='14'>
<Link
href={appRoutes.newPromotionCondition.makePath({
Expand All @@ -77,34 +83,6 @@ function Page(
)
}

function PromotionRuleDetail({
promotionRule,
onRemove
}: {
promotionRule: PromotionRule
onRemove: () => void
}): JSX.Element | null {
const formLabels = useMemo(() => toFormLabels(promotionRule), [promotionRule])

switch (promotionRule.type) {
case 'custom_promotion_rules':
return (
<div>
{formLabels?.map((formLabel) => (
<CustomPromotionRuleItem
key={formLabel.predicate}
onRemove={onRemove}
customPromotionRule={promotionRule}
formLabel={formLabel}
/>
))}
</div>
)
default:
return null
}
}

function CustomPromotionRuleItem({
formLabel,
customPromotionRule,
Expand All @@ -131,52 +109,10 @@ function CustomPromotionRuleItem({
console.log('removing', formLabel.predicate, 'from filters')
}
: undefined
if (formLabel.rel != null) {
return (
<ConditionItemWithRelationships
rel={formLabel.rel}
ids={values}
label={label}
onRemove={handleRemove}
/>
)
}

return <ConditionItem label={label} onRemove={handleRemove} values={values} />
}

function ConditionItemWithRelationships({
rel,
label,
ids,
onRemove
}: {
rel: Extract<ListableResourceType, 'markets' | 'tags'>
label: string
ids: string[]
onRemove?: () => void
}): JSX.Element | null {
const { data } = useCoreApi(
rel,
'list',
[{ filters: { id_in: ids.join(',') } }],
{
revalidateIfStale: false,
revalidateOnFocus: false,
revalidateOnMount: true,
revalidateOnReconnect: false
}
)

return (
<ConditionItem
label={label}
onRemove={onRemove}
values={data?.map((d) => d.name) ?? []}
/>
)
}

function ConditionItem({
label,
values,
Expand Down
10 changes: 9 additions & 1 deletion packages/app/src/pages/PromotionDetailsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Promotion } from '#data/dictionaries/promotion'
import { appRoutes } from '#data/routes'
import { getCurrencyCodes, usePromotionRules } from '#data/ruleBuilder/config'
import { usePromotion } from '#hooks/usePromotion'
import {
Badge,
Expand Down Expand Up @@ -35,6 +36,9 @@ function Page(
const [, setLocation] = useLocation()

const { promotion, isLoading } = usePromotion(props.params.promotionId)
const { data: rules } = usePromotionRules(promotion)

console.log('available currency codes', getCurrencyCodes(promotion))

return (
<PageLayout
Expand Down Expand Up @@ -93,7 +97,11 @@ function Page(
</Link>
}
>
<ListDetailsItem label='??'>??</ListDetailsItem>
{rules?.map((rule) => (
<ListDetailsItem key={rule.predicate} label={rule.parameter}>
{rule.value.split(',').join(', ')}
</ListDetailsItem>
))}
</Section>
</Spacer>
</SkeletonTemplate>
Expand Down
12 changes: 2 additions & 10 deletions packages/app/src/pages/PromotionListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ import {
useResourceFilters,
useTokenProvider
} from '@commercelayer/app-elements'
import { Link, useLocation } from 'wouter'
import { useLocation } from 'wouter'
import { navigate, useSearch } from 'wouter/use-location'

function Page(): JSX.Element {
const {
settings: { mode },
canUser
settings: { mode }
} = useTokenProvider()

const queryString = useSearch()
Expand Down Expand Up @@ -88,13 +87,6 @@ function Page(): JSX.Element {
}
/>
}
actionButton={
canUser('create', 'promotions') ? (
<Link href={appRoutes.newSelectType.makePath({})}>
<a>Add new</a>
</Link>
) : undefined
}
/>
</Spacer>
</PageLayout>
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 30e1d52

Please sign in to comment.