diff --git a/app/bot/src/listing/build-listing-embed.ts b/app/bot/src/listing/build-listing-embed.ts index ea87f50a2..acb42bc6a 100644 --- a/app/bot/src/listing/build-listing-embed.ts +++ b/app/bot/src/listing/build-listing-embed.ts @@ -15,9 +15,7 @@ export function buildListingEmbed(listing: Listing, creator: UserDocument) { .setDescription(i18next.t('listing.embed.description', { user: userMention(creator.discord.id) })) .setColor(0x00ff66) .setFields(fields(listing.items, listing.target)) - .setURL( - frontendRoutes.listing.details.withQuery({ listing: listing }).getUrl({ slug: listing.target.collection.slug }) - ) + .setURL(frontendRoutes.listing.details.getUrl({ slug: listing.slug })) } function fields(items: NonEmptyArray, target: Listing['target']): APIEmbedField[] { diff --git a/app/bot/src/listing/build-listing-link-button.ts b/app/bot/src/listing/build-listing-link-button.ts index c17b9d269..43adef698 100644 --- a/app/bot/src/listing/build-listing-link-button.ts +++ b/app/bot/src/listing/build-listing-link-button.ts @@ -7,7 +7,7 @@ export function buildListingLinkButton(listing: Listing) { return new ActionRowBuilder().addComponents( new ButtonBuilder() .setLabel(i18next.t('listing.button')) - .setURL(frontendRoutes.listing.details.withQuery({ listing }).getUrl({ slug: listing.target.collection.slug })) + .setURL(frontendRoutes.listing.details.getUrl({ slug: listing.slug })) .setStyle(ButtonStyle.Link) ) } diff --git a/app/bot/src/offer/build-offer-link-button.ts b/app/bot/src/offer/build-offer-link-button.ts index 827defd23..5a7d666fe 100644 --- a/app/bot/src/offer/build-offer-link-button.ts +++ b/app/bot/src/offer/build-offer-link-button.ts @@ -7,7 +7,7 @@ export function buildOfferLinkButton(offer: Offer) { return new ActionRowBuilder().addComponents( new ButtonBuilder() .setLabel(i18next.t('offer.button')) - .setURL(frontendRoutes.offer.details.withQuery({ offer }).getUrl({ username: offer.sender.username })) + .setURL(frontendRoutes.offer.details.getUrl({ slug: offer.slug })) .setStyle(ButtonStyle.Link) ) } diff --git a/app/bot/test/listing/build-listing-link-button.test.ts b/app/bot/test/listing/build-listing-link-button.test.ts index 9622f9fbc..9ecf2337a 100644 --- a/app/bot/test/listing/build-listing-link-button.test.ts +++ b/app/bot/test/listing/build-listing-link-button.test.ts @@ -12,7 +12,7 @@ describe('builders - buildNewListingButtons', () => { it('should build a new listing button with a link to the listing', () => { const result = buildListingLinkButton(listingMock) - const expectedLink = 'https://undefined/collection/pxmythics-genesis?listing=juzmtpgkm62mmhecmbn4' + const expectedLink = 'https://undefined/listing/juzmtpgkm62mmhecmbn4' expect(result).toBeInstanceOf(ActionRowBuilder) const components = result.components expect(components).toHaveLength(1) diff --git a/app/frontend/src/app/collection/[slug]/page.tsx b/app/frontend/src/app/collection/[slug]/page.tsx index 9d74ec956..a0849d43f 100644 --- a/app/frontend/src/app/collection/[slug]/page.tsx +++ b/app/frontend/src/app/collection/[slug]/page.tsx @@ -14,8 +14,6 @@ import { toSwapsWithRole } from '@echo/frontend/lib/helpers/swap/to-swaps-with-r import type { Collection } from '@echo/model/types/collection' import type { OwnedNft } from '@echo/model/types/nft' import type { User } from '@echo/model/types/user' -import type { ListingDetailsSearchParams } from '@echo/routing/types/frontend/search-params/listing-details-search-params' -import { listingDetailsSearchParamsTransformSchema } from '@echo/routing/validators/frontend/listing/listing-details-search-params-transform-schema' import { CollectionPage } from '@echo/ui/pages/collection/collection-page' import type { Nullable } from '@echo/utils/types/nullable' import { notFound } from 'next/navigation' @@ -25,11 +23,10 @@ interface Props { params: { slug: Lowercase } - searchParams?: ListingDetailsSearchParams user: Nullable } -async function render({ params: { slug }, searchParams, user }: Props) { +async function render({ params: { slug }, user }: Props) { const collection = await pipe( getCollection, otherwise>(pipe(captureAndLogError, always(undefined))) @@ -45,7 +42,6 @@ async function render({ params: { slug }, searchParams, user }: Props) { const listings = await pipe(getListingsForCollection, andThen(toListingsWithRole(user)), otherwiseEmptyArray)(slug) const offers = await pipe(getOffersForCollection, andThen(toOffersWithRole(user)), otherwiseEmptyArray)(slug) const swaps = await pipe(getSwapsForCollection, andThen(toSwapsWithRole(user)), otherwiseEmptyArray)(slug) - const selection = listingDetailsSearchParamsTransformSchema.parse({ listings, searchParams }) return ( ) } diff --git a/app/frontend/src/app/listing/[slug]/loading.tsx b/app/frontend/src/app/listing/[slug]/loading.tsx new file mode 100644 index 000000000..5439e9341 --- /dev/null +++ b/app/frontend/src/app/listing/[slug]/loading.tsx @@ -0,0 +1,11 @@ +import { HeaderSkeleton } from '@echo/ui/components/base/header/skeleton/header-skeleton' +import { PageLayout } from '@echo/ui/components/base/layout/page-layout' + +export default function ListingLoading() { + return ( + + + {/* TODO Skeleton view for listing details */} + + ) +} diff --git a/app/frontend/src/app/listing/[slug]/page.tsx b/app/frontend/src/app/listing/[slug]/page.tsx new file mode 100644 index 000000000..4f9862bf9 --- /dev/null +++ b/app/frontend/src/app/listing/[slug]/page.tsx @@ -0,0 +1,38 @@ +import { getListing } from '@echo/firestore/crud/listing/get-listing' +import { withUser } from '@echo/frontend/lib/decorators/with-user' +import { toListingWithRole } from '@echo/frontend/lib/helpers/listing/to-listing-with-role' +import type { User } from '@echo/model/types/user' +import { Header } from '@echo/ui/components/base/header/header' +import { MainSectionLayout } from '@echo/ui/components/base/layout/main-section-layout' +import { PageLayout } from '@echo/ui/components/base/layout/page-layout' +import { ListingDetails } from '@echo/ui/components/listing/details/listing-details' +import { unlessNil } from '@echo/utils/helpers/unless-nil' +import type { Nullable } from '@echo/utils/types/nullable' +import { notFound } from 'next/navigation' +import { andThen, isNil, pipe } from 'ramda' + +interface ListingPageProps { + params: { + slug: Lowercase + } + user: Nullable +} + +async function render({ params: { slug }, user }: ListingPageProps) { + const listing = await pipe(getListing, andThen(unlessNil(toListingWithRole(user))))(slug) + + if (isNil(listing)) { + notFound() + } + + return ( + +
+ + + + + ) +} + +export default withUser(render) diff --git a/app/frontend/src/app/me/page.tsx b/app/frontend/src/app/me/page.tsx index ed3de1ee5..18c62b0b2 100644 --- a/app/frontend/src/app/me/page.tsx +++ b/app/frontend/src/app/me/page.tsx @@ -11,8 +11,6 @@ import { toOffersWithRole } from '@echo/frontend/lib/helpers/offer/to-offers-wit import { otherwiseEmptyArray } from '@echo/frontend/lib/helpers/otherwise-empty-array' import { toSwapsWithRole } from '@echo/frontend/lib/helpers/swap/to-swaps-with-role' import type { User } from '@echo/model/types/user' -import type { SwapDetailsSearchParams } from '@echo/routing/types/frontend/search-params/swap-details-search-params' -import { swapDetailsSearchParamsTransformSchema } from '@echo/routing/validators/frontend/swap/swap-details-search-params-transform-schema' import { ProfilePage } from '@echo/ui/pages/profile/profile-page' import type { OfferWithRole } from '@echo/ui/types/offer-with-role' import pFilter from 'p-filter' @@ -20,10 +18,9 @@ import { always, andThen, otherwise, pipe, prop } from 'ramda' interface Props { user: User - searchParams?: SwapDetailsSearchParams } -async function render({ user, searchParams }: Props) { +async function render({ user }: Props) { const nfts = await pipe(prop('username'), getNftsForOwner, otherwiseEmptyArray)(user) const listings = await pipe( prop('username'), @@ -46,7 +43,6 @@ async function render({ user, searchParams }: Props) { const redeemableOffers = await pFilter(offers, isOfferRedeemable(user.username)) const offersCount = await pipe(prop('username'), getUserOffersCount, otherwise(always(0)))(user) const swaps = await pipe(prop('username'), getSwapsForUser, andThen(toSwapsWithRole(user)), otherwiseEmptyArray)(user) - const selection = swapDetailsSearchParamsTransformSchema.parse({ swaps, searchParams }) return ( ) } diff --git a/app/frontend/src/app/offer/[slug]/loading.tsx b/app/frontend/src/app/offer/[slug]/loading.tsx new file mode 100644 index 000000000..2df0b8b00 --- /dev/null +++ b/app/frontend/src/app/offer/[slug]/loading.tsx @@ -0,0 +1,11 @@ +import { HeaderSkeleton } from '@echo/ui/components/base/header/skeleton/header-skeleton' +import { PageLayout } from '@echo/ui/components/base/layout/page-layout' + +export default function OfferLoading() { + return ( + + + {/* TODO Skeleton view for offer details */} + + ) +} diff --git a/app/frontend/src/app/offer/[slug]/page.tsx b/app/frontend/src/app/offer/[slug]/page.tsx new file mode 100644 index 000000000..d9cdb3473 --- /dev/null +++ b/app/frontend/src/app/offer/[slug]/page.tsx @@ -0,0 +1,38 @@ +import { getOffer } from '@echo/firestore/crud/offer/get-offer' +import { withUser } from '@echo/frontend/lib/decorators/with-user' +import { toOfferWithRole } from '@echo/frontend/lib/helpers/offer/to-offer-with-role' +import type { User } from '@echo/model/types/user' +import { Header } from '@echo/ui/components/base/header/header' +import { MainSectionLayout } from '@echo/ui/components/base/layout/main-section-layout' +import { PageLayout } from '@echo/ui/components/base/layout/page-layout' +import { OfferDetails } from '@echo/ui/components/offer/details/offer-details' +import { unlessNil } from '@echo/utils/helpers/unless-nil' +import type { Nullable } from '@echo/utils/types/nullable' +import { notFound } from 'next/navigation' +import { andThen, isNil, pipe } from 'ramda' + +interface OfferPageProps { + params: { + slug: Lowercase + } + user: Nullable +} + +async function render({ params: { slug }, user }: OfferPageProps) { + const offer = await pipe(getOffer, andThen(unlessNil(toOfferWithRole(user))))(slug) + + if (isNil(offer)) { + notFound() + } + + return ( + +
+ + + + + ) +} + +export default withUser(render) diff --git a/app/frontend/src/app/swap/[slug]/loading.tsx b/app/frontend/src/app/swap/[slug]/loading.tsx new file mode 100644 index 000000000..84780ea99 --- /dev/null +++ b/app/frontend/src/app/swap/[slug]/loading.tsx @@ -0,0 +1,11 @@ +import { HeaderSkeleton } from '@echo/ui/components/base/header/skeleton/header-skeleton' +import { PageLayout } from '@echo/ui/components/base/layout/page-layout' + +export default function SwapLoading() { + return ( + + + {/* TODO Skeleton view for swap details */} + + ) +} diff --git a/app/frontend/src/app/swap/[slug]/page.tsx b/app/frontend/src/app/swap/[slug]/page.tsx new file mode 100644 index 000000000..abd9a0411 --- /dev/null +++ b/app/frontend/src/app/swap/[slug]/page.tsx @@ -0,0 +1,38 @@ +import { getSwap } from '@echo/firestore/crud/swap/get-swap' +import { withUser } from '@echo/frontend/lib/decorators/with-user' +import { toSwapWithRole } from '@echo/frontend/lib/helpers/swap/to-swap-with-role' +import type { User } from '@echo/model/types/user' +import { Header } from '@echo/ui/components/base/header/header' +import { MainSectionLayout } from '@echo/ui/components/base/layout/main-section-layout' +import { PageLayout } from '@echo/ui/components/base/layout/page-layout' +import { SwapDetails } from '@echo/ui/components/swap/details/swap-details' +import { unlessNil } from '@echo/utils/helpers/unless-nil' +import type { Nullable } from '@echo/utils/types/nullable' +import { notFound } from 'next/navigation' +import { andThen, isNil, pipe } from 'ramda' + +interface SwapPageProps { + params: { + slug: Lowercase + } + user: Nullable +} + +async function render({ params: { slug }, user }: SwapPageProps) { + const swap = await pipe(getSwap, andThen(unlessNil(toSwapWithRole(user))))(slug) + + if (isNil(swap)) { + notFound() + } + + return ( + +
+ + + + + ) +} + +export default withUser(render) diff --git a/app/frontend/src/app/user/[username]/page.tsx b/app/frontend/src/app/user/[username]/page.tsx index 5676866fc..d3720140c 100644 --- a/app/frontend/src/app/user/[username]/page.tsx +++ b/app/frontend/src/app/user/[username]/page.tsx @@ -12,8 +12,6 @@ import { otherwiseEmptyArray } from '@echo/frontend/lib/helpers/otherwise-empty- import { otherwiseUndefined } from '@echo/frontend/lib/helpers/otherwise-undefined' import { toSwapsWithRole } from '@echo/frontend/lib/helpers/swap/to-swaps-with-role' import type { User } from '@echo/model/types/user' -import type { OfferDetailsSearchParams } from '@echo/routing/types/frontend/search-params/offer-details-search-params' -import { offerDetailsSearchParamsTransformSchema } from '@echo/routing/validators/frontend/offer/offer-details-search-params-transform-schema' import { UserPage } from '@echo/ui/pages/user/user-page' import type { Nullable } from '@echo/utils/types/nullable' import { notFound } from 'next/navigation' @@ -23,11 +21,10 @@ interface Props { params: { username: string } - searchParams?: OfferDetailsSearchParams user: Nullable } -async function render({ params: { username }, searchParams, user: authUser }: Props) { +async function render({ params: { username }, user: authUser }: Props) { const user = await pipe(getUserByUsername, otherwiseUndefined)(username) if (isNil(user)) { notFound() @@ -42,7 +39,6 @@ async function render({ params: { username }, searchParams, user: authUser }: Pr const offers = await pipe(getPendingOffersForUser, andThen(toOffersWithRole(authUser)), otherwiseEmptyArray)(username) const offersCount = await pipe(getUserOffersCount, otherwise(pipe(captureAndLogError, always(0))))(username) const swaps = await pipe(getSwapsForUser, andThen(toSwapsWithRole(user)), otherwiseEmptyArray)(username) - const selection = offerDetailsSearchParamsTransformSchema.parse({ offers, searchParams }) return ( ) } diff --git a/app/frontend/src/lib/helpers/listing/to-listing-with-role.ts b/app/frontend/src/lib/helpers/listing/to-listing-with-role.ts new file mode 100644 index 000000000..839438713 --- /dev/null +++ b/app/frontend/src/lib/helpers/listing/to-listing-with-role.ts @@ -0,0 +1,12 @@ +import { listingDocumentToModel } from '@echo/firestore/converters/listing-document-to-model' +import type { ListingDocument } from '@echo/firestore/types/model/listing-document' +import type { User } from '@echo/model/types/user' +import { setListingRoleForUser } from '@echo/ui/helpers/listing/set-listing-role-for-user' +import type { Nullable } from '@echo/utils/types/nullable' +import { pipe } from 'ramda' + +export function toListingWithRole(user: Nullable) { + return function (listing: ListingDocument) { + return pipe(listingDocumentToModel, setListingRoleForUser(user))(listing) + } +} diff --git a/app/frontend/src/lib/helpers/listing/to-listings-with-role.ts b/app/frontend/src/lib/helpers/listing/to-listings-with-role.ts index 100115fc3..df2ee020b 100644 --- a/app/frontend/src/lib/helpers/listing/to-listings-with-role.ts +++ b/app/frontend/src/lib/helpers/listing/to-listings-with-role.ts @@ -1,13 +1,12 @@ -import { listingDocumentToModel } from '@echo/firestore/converters/listing-document-to-model' import type { ListingDocument } from '@echo/firestore/types/model/listing-document' +import { toListingWithRole } from '@echo/frontend/lib/helpers/listing/to-listing-with-role' import type { User } from '@echo/model/types/user' -import { setListingRoleForUser } from '@echo/ui/helpers/listing/set-listing-role-for-user' import { promiseAll } from '@echo/utils/helpers/promise-all' import type { Nullable } from '@echo/utils/types/nullable' -import { map, pipe } from 'ramda' +import { map } from 'ramda' export function toListingsWithRole(user: Nullable) { return function (listings: ListingDocument[]) { - return pipe(map(pipe(listingDocumentToModel, setListingRoleForUser(user))), promiseAll)(listings) + return promiseAll(map(toListingWithRole(user), listings)) } } diff --git a/app/frontend/src/lib/helpers/offer/to-offer-with-role.ts b/app/frontend/src/lib/helpers/offer/to-offer-with-role.ts new file mode 100644 index 000000000..8ac0ac3cf --- /dev/null +++ b/app/frontend/src/lib/helpers/offer/to-offer-with-role.ts @@ -0,0 +1,12 @@ +import { offerDocumentToModel } from '@echo/firestore/converters/offer-document-to-model' +import type { OfferDocument } from '@echo/firestore/types/model/offer-document' +import type { User } from '@echo/model/types/user' +import { setOfferRoleForUser } from '@echo/ui/helpers/offer/set-offer-role-for-user' +import type { Nullable } from '@echo/utils/types/nullable' +import { pipe } from 'ramda' + +export function toOfferWithRole(user: Nullable) { + return function (offer: OfferDocument) { + return pipe(offerDocumentToModel, setOfferRoleForUser(user))(offer) + } +} diff --git a/app/frontend/src/lib/helpers/offer/to-offers-with-role.ts b/app/frontend/src/lib/helpers/offer/to-offers-with-role.ts index d58ce0064..2570cd8db 100644 --- a/app/frontend/src/lib/helpers/offer/to-offers-with-role.ts +++ b/app/frontend/src/lib/helpers/offer/to-offers-with-role.ts @@ -1,12 +1,11 @@ -import { offerDocumentToModel } from '@echo/firestore/converters/offer-document-to-model' import type { OfferDocument } from '@echo/firestore/types/model/offer-document' +import { toOfferWithRole } from '@echo/frontend/lib/helpers/offer/to-offer-with-role' import type { User } from '@echo/model/types/user' -import { setOfferRoleForUser } from '@echo/ui/helpers/offer/set-offer-role-for-user' import type { Nullable } from '@echo/utils/types/nullable' -import { map, pipe } from 'ramda' +import { map } from 'ramda' export function toOffersWithRole(user: Nullable) { return function (offers: OfferDocument[]) { - return map(pipe(offerDocumentToModel, setOfferRoleForUser(user)), offers) + return map(toOfferWithRole(user))(offers) } } diff --git a/app/frontend/src/lib/helpers/swap/to-swap-with-role.ts b/app/frontend/src/lib/helpers/swap/to-swap-with-role.ts new file mode 100644 index 000000000..a85753a9b --- /dev/null +++ b/app/frontend/src/lib/helpers/swap/to-swap-with-role.ts @@ -0,0 +1,12 @@ +import { swapDocumentToModel } from '@echo/firestore/converters/swap-document-to-model' +import type { SwapDocument } from '@echo/firestore/types/model/swap-document' +import type { User } from '@echo/model/types/user' +import { setSwapRoleForUser } from '@echo/ui/helpers/swap/set-swap-role-for-user' +import type { Nullable } from '@echo/utils/types/nullable' +import { pipe } from 'ramda' + +export function toSwapWithRole(user: Nullable) { + return function (swap: SwapDocument) { + return pipe(swapDocumentToModel, setSwapRoleForUser(user))(swap) + } +} diff --git a/app/frontend/src/lib/helpers/swap/to-swaps-with-role.ts b/app/frontend/src/lib/helpers/swap/to-swaps-with-role.ts index 8b620c26f..582e7659b 100644 --- a/app/frontend/src/lib/helpers/swap/to-swaps-with-role.ts +++ b/app/frontend/src/lib/helpers/swap/to-swaps-with-role.ts @@ -1,12 +1,11 @@ -import { swapDocumentToModel } from '@echo/firestore/converters/swap-document-to-model' import type { SwapDocument } from '@echo/firestore/types/model/swap-document' +import { toSwapWithRole } from '@echo/frontend/lib/helpers/swap/to-swap-with-role' import type { User } from '@echo/model/types/user' -import { setSwapRoleForUser } from '@echo/ui/helpers/swap/set-swap-role-for-user' import type { Nullable } from '@echo/utils/types/nullable' -import { map, pipe } from 'ramda' +import { map } from 'ramda' export function toSwapsWithRole(user: Nullable) { return function (swaps: SwapDocument[]) { - return map(pipe(swapDocumentToModel, setSwapRoleForUser(user)), swaps) + return map(toSwapWithRole(user))(swaps) } } diff --git a/app/storybook/src/listing/details/listing-details.stories.tsx b/app/storybook/src/listing/details/listing-details.stories.tsx index 308416332..37c18aeff 100644 --- a/app/storybook/src/listing/details/listing-details.stories.tsx +++ b/app/storybook/src/listing/details/listing-details.stories.tsx @@ -15,7 +15,6 @@ import { type FunctionComponent, useEffect, useState } from 'react' interface Props { state: ListingState role: ListingRole | 'none' - onClose: VoidFunction } type ComponentType = FunctionComponent @@ -34,11 +33,6 @@ const metadata: Meta = { state: { options: values(ListingState), control: { type: 'select' } - }, - onClose: { - table: { - disable: true - } } } } @@ -46,7 +40,7 @@ const metadata: Meta = { export default metadata export const Details: StoryObj = { - render: ({ state, role, onClose }) => { + render: ({ state, role }) => { const [listing, setListing] = useState(assoc('role', undefined, listingMock)) function setExpirationAndLocked(listing: ListingWithRole): ListingWithRole { @@ -73,14 +67,6 @@ export const Details: StoryObj = { setListing(pipe(assoc('state', state), setExpirationAndLocked, setRole)) }, [state, role]) - return ( - { - setListing(setRole(listing)) - }} - onClose={onClose} - /> - ) + return } } diff --git a/app/storybook/src/offer/details/offer-details.stories.tsx b/app/storybook/src/offer/details/offer-details.stories.tsx index e8938cbca..ec48ae142 100644 --- a/app/storybook/src/offer/details/offer-details.stories.tsx +++ b/app/storybook/src/offer/details/offer-details.stories.tsx @@ -33,21 +33,6 @@ const metadata: Meta = { role: { options: pipe(values, append('none'))(OfferRole), control: { type: 'radio' } - }, - onClose: { - table: { - disable: true - } - }, - onRedeem: { - table: { - disable: true - } - }, - onSwap: { - table: { - disable: true - } } } } @@ -55,7 +40,7 @@ const metadata: Meta = { export default metadata export const Details: StoryObj = { - render: ({ state, role, onClose, onRedeem, onSwap }) => { + render: ({ state, role }) => { const [offer, setOffer] = useState(assoc('role', undefined, offerMockToJohnnycage)) function setExpirationAndLocked(offer: OfferWithRole): OfferWithRole { @@ -82,16 +67,6 @@ export const Details: StoryObj = { setOffer(pipe(assoc('state', state), setExpirationAndLocked, setRole)) }, [state, role]) - return ( - { - setOffer(setRole(offer)) - }} - /> - ) + return } } diff --git a/app/storybook/src/pages/collection/collection-page.stories.tsx b/app/storybook/src/pages/collection/collection-page.stories.tsx index 073ff0d97..6725e49eb 100644 --- a/app/storybook/src/pages/collection/collection-page.stories.tsx +++ b/app/storybook/src/pages/collection/collection-page.stories.tsx @@ -50,9 +50,3 @@ const metadata: Meta = { export default metadata export const Page: StoryObj = {} - -export const WithSelectedListing: StoryObj = { - args: { - selection: 0 - } -} diff --git a/app/storybook/src/pages/profile/profile-page.stories.tsx b/app/storybook/src/pages/profile/profile-page.stories.tsx index f03d5595b..46f7fde65 100644 --- a/app/storybook/src/pages/profile/profile-page.stories.tsx +++ b/app/storybook/src/pages/profile/profile-page.stories.tsx @@ -36,9 +36,3 @@ const metadata: Meta = { export default metadata export const Page: StoryObj = {} - -export const WithSelectedSwap: StoryObj = { - args: { - selection: 0 - } -} diff --git a/app/storybook/src/pages/user/user-page.stories.tsx b/app/storybook/src/pages/user/user-page.stories.tsx index 114351312..4155bc5a6 100644 --- a/app/storybook/src/pages/user/user-page.stories.tsx +++ b/app/storybook/src/pages/user/user-page.stories.tsx @@ -50,9 +50,3 @@ const metadata: Meta = { export default metadata export const Page: StoryObj = {} - -export const WithSelectedOffer: StoryObj = { - args: { - selection: 0 - } -} diff --git a/app/storybook/src/swap/swap-details.stories.tsx b/app/storybook/src/swap/swap-details.stories.tsx index 36c9cddb6..c859eebef 100644 --- a/app/storybook/src/swap/swap-details.stories.tsx +++ b/app/storybook/src/swap/swap-details.stories.tsx @@ -24,11 +24,6 @@ const metadata: Meta = { role: { options: pipe(values, append('none'))(OfferRole), control: { type: 'radio' } - }, - onClose: { - table: { - disable: true - } } } } @@ -36,7 +31,7 @@ const metadata: Meta = { export default metadata export const Details: StoryObj = { - render: ({ role, onClose }) => { + render: ({ role }) => { const [swap, setSwap] = useState(assoc('role', undefined, swapMock)) function setRole(swap: Swap | SwapWithRole): SwapWithRole { @@ -53,6 +48,6 @@ export const Details: StoryObj = { setSwap(setRole) }, [role]) - return + return } } diff --git a/lib/routing/src/constants/frontend-routes.ts b/lib/routing/src/constants/frontend-routes.ts index cea6b1b78..3ae219017 100644 --- a/lib/routing/src/constants/frontend-routes.ts +++ b/lib/routing/src/constants/frontend-routes.ts @@ -1,19 +1,10 @@ import { FrontendRoute } from '@echo/routing/services/frontend/frontend-route' import type { CreateListingQueryParams } from '@echo/routing/types/frontend/query-params/create-listing-query-params' import type { CreateOfferQueryParams } from '@echo/routing/types/frontend/query-params/create-offer-query-params' -import type { ListingDetailsQueryParams } from '@echo/routing/types/frontend/query-params/listing-details-query-params' -import type { OfferDetailsQueryParams } from '@echo/routing/types/frontend/query-params/offer-details-query-params' -import type { SwapDetailsQueryParams } from '@echo/routing/types/frontend/query-params/swap-details-query-params' import type { CreateListingSearchParams } from '@echo/routing/types/frontend/search-params/create-listing-search-params' import type { CreateOfferSearchParams } from '@echo/routing/types/frontend/search-params/create-offer-search-params' -import type { ListingDetailsSearchParams } from '@echo/routing/types/frontend/search-params/listing-details-search-params' -import type { OfferDetailsSearchParams } from '@echo/routing/types/frontend/search-params/offer-details-search-params' -import type { SwapDetailsSearchParams } from '@echo/routing/types/frontend/search-params/swap-details-search-params' import { createListingQueryParamsTransformSchema } from '@echo/routing/validators/frontend/listing/create-listing-query-params-transform-schema' -import { listingDetailsSearchParamsSchema } from '@echo/routing/validators/frontend/listing/listing-details-search-params-schema' import { createOfferQueryParamsTransformSchema } from '@echo/routing/validators/frontend/offer/create-offer-query-params-transform-schema' -import { offerDetailsSearchParamsSchema } from '@echo/routing/validators/frontend/offer/offer-details-search-params-schema' -import { swapDetailsSearchParamsSchema } from '@echo/routing/validators/frontend/swap/swap-details-search-params-schema' export const frontendRoutes = { base: { @@ -29,13 +20,7 @@ export const frontendRoutes = { { secure: true }, (params: CreateListingQueryParams) => createListingQueryParamsTransformSchema.parse(params) ), - details: new FrontendRoute< - Record<'slug', Lowercase>, - ListingDetailsQueryParams, - ListingDetailsSearchParams - >('/collection/:slug', { secure: false }, (params: ListingDetailsQueryParams) => - listingDetailsSearchParamsSchema.parse(params) - ) + details: new FrontendRoute>>('/listing/:slug', { secure: false }) }, login: { discord: new FrontendRoute('/login/discord', { secure: false }), @@ -49,18 +34,10 @@ export const frontendRoutes = { { secure: true }, (params: CreateOfferQueryParams) => createOfferQueryParamsTransformSchema.parse(params) ), - details: new FrontendRoute, OfferDetailsQueryParams, OfferDetailsSearchParams>( - '/user/:username', - { secure: false }, - (params: OfferDetailsQueryParams) => offerDetailsSearchParamsSchema.parse(params) - ) + details: new FrontendRoute>>('/offer/:slug', { secure: false }) }, swap: { - details: new FrontendRoute( - '/me', - { secure: true }, - (params: SwapDetailsQueryParams) => swapDetailsSearchParamsSchema.parse(params) - ) + details: new FrontendRoute>>('/swap/:slug', { secure: false }) }, user: { details: new FrontendRoute>('/user/:username', { secure: false }), diff --git a/lib/routing/src/types/frontend/query-params/listing-details-query-params.ts b/lib/routing/src/types/frontend/query-params/listing-details-query-params.ts deleted file mode 100644 index f3c1ab7b7..000000000 --- a/lib/routing/src/types/frontend/query-params/listing-details-query-params.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { listingDetailsQueryParamsSchema } from '@echo/routing/validators/frontend/listing/listing-details-query-params-schema' -import { z } from 'zod' - -export type ListingDetailsQueryParams = z.infer diff --git a/lib/routing/src/types/frontend/query-params/offer-details-query-params.ts b/lib/routing/src/types/frontend/query-params/offer-details-query-params.ts deleted file mode 100644 index 13170431b..000000000 --- a/lib/routing/src/types/frontend/query-params/offer-details-query-params.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { offerDetailsQueryParamsSchema } from '@echo/routing/validators/frontend/offer/offer-details-query-params-schema' -import { z } from 'zod' - -export type OfferDetailsQueryParams = z.infer diff --git a/lib/routing/src/types/frontend/query-params/swap-details-query-params.ts b/lib/routing/src/types/frontend/query-params/swap-details-query-params.ts deleted file mode 100644 index 1e8246452..000000000 --- a/lib/routing/src/types/frontend/query-params/swap-details-query-params.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { swapDetailsQueryParamsSchema } from '@echo/routing/validators/frontend/swap/swap-details-query-params-schema' -import { z } from 'zod' - -export type SwapDetailsQueryParams = z.infer diff --git a/lib/routing/src/types/frontend/search-params/listing-details-search-params.ts b/lib/routing/src/types/frontend/search-params/listing-details-search-params.ts deleted file mode 100644 index 30ee9801a..000000000 --- a/lib/routing/src/types/frontend/search-params/listing-details-search-params.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { listingDetailsSearchParamsSchema } from '@echo/routing/validators/frontend/listing/listing-details-search-params-schema' -import { z } from 'zod' - -export type ListingDetailsSearchParams = z.infer diff --git a/lib/routing/src/types/frontend/search-params/offer-details-search-params.ts b/lib/routing/src/types/frontend/search-params/offer-details-search-params.ts deleted file mode 100644 index cc6c2b355..000000000 --- a/lib/routing/src/types/frontend/search-params/offer-details-search-params.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { offerDetailsSearchParamsSchema } from '@echo/routing/validators/frontend/offer/offer-details-search-params-schema' -import { z } from 'zod' - -export type OfferDetailsSearchParams = z.infer diff --git a/lib/routing/src/types/frontend/search-params/swap-details-search-params.ts b/lib/routing/src/types/frontend/search-params/swap-details-search-params.ts deleted file mode 100644 index ec36e5e50..000000000 --- a/lib/routing/src/types/frontend/search-params/swap-details-search-params.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { swapDetailsSearchParamsSchema } from '@echo/routing/validators/frontend/swap/swap-details-search-params-schema' -import { z } from 'zod' - -export type SwapDetailsSearchParams = z.infer diff --git a/lib/routing/src/validators/frontend/listing/listing-details-query-params-schema.ts b/lib/routing/src/validators/frontend/listing/listing-details-query-params-schema.ts deleted file mode 100644 index 5215483a1..000000000 --- a/lib/routing/src/validators/frontend/listing/listing-details-query-params-schema.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { withSlugSchema } from '@echo/model/validators/slug-schema' -import { object } from 'zod' - -export const listingDetailsQueryParamsSchema = object({ - listing: withSlugSchema -}) diff --git a/lib/routing/src/validators/frontend/listing/listing-details-search-params-schema.ts b/lib/routing/src/validators/frontend/listing/listing-details-search-params-schema.ts deleted file mode 100644 index 920703cc3..000000000 --- a/lib/routing/src/validators/frontend/listing/listing-details-search-params-schema.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { serializeListingSchema } from '@echo/model/validators/listing-schema' -import { object } from 'zod' - -export const listingDetailsSearchParamsSchema = object({ - listing: serializeListingSchema -}).strict() diff --git a/lib/routing/src/validators/frontend/listing/listing-details-search-params-transform-schema.ts b/lib/routing/src/validators/frontend/listing/listing-details-search-params-transform-schema.ts deleted file mode 100644 index 6066cf457..000000000 --- a/lib/routing/src/validators/frontend/listing/listing-details-search-params-transform-schema.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { listingSchema } from '@echo/model/validators/listing-schema' -import { slugSchema } from '@echo/model/validators/slug-schema' -import { findIndex, isEmpty, isNil, propEq } from 'ramda' -import { object } from 'zod' - -export const listingDetailsSearchParamsTransformSchema = object({ - listings: listingSchema.array(), - searchParams: object({ - listing: slugSchema.optional() - }) -}).transform(({ listings, searchParams }) => { - if (isEmpty(searchParams) || isNil(searchParams.listing)) { - return undefined - } - const index = findIndex(propEq(searchParams.listing, 'slug'), listings) - if (index === -1) { - return undefined - } - return index -}) diff --git a/lib/routing/src/validators/frontend/offer/offer-details-query-params-schema.ts b/lib/routing/src/validators/frontend/offer/offer-details-query-params-schema.ts deleted file mode 100644 index 5e6d10642..000000000 --- a/lib/routing/src/validators/frontend/offer/offer-details-query-params-schema.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { withSlugSchema } from '@echo/model/validators/slug-schema' -import { object } from 'zod' - -export const offerDetailsQueryParamsSchema = object({ - offer: withSlugSchema -}) diff --git a/lib/routing/src/validators/frontend/offer/offer-details-search-params-schema.ts b/lib/routing/src/validators/frontend/offer/offer-details-search-params-schema.ts deleted file mode 100644 index 25ae62a22..000000000 --- a/lib/routing/src/validators/frontend/offer/offer-details-search-params-schema.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { serializeOfferSchema } from '@echo/model/validators/offer-schema' -import { object } from 'zod' - -export const offerDetailsSearchParamsSchema = object({ - offer: serializeOfferSchema -}).strict() diff --git a/lib/routing/src/validators/frontend/offer/offer-details-search-params-transform-schema.ts b/lib/routing/src/validators/frontend/offer/offer-details-search-params-transform-schema.ts deleted file mode 100644 index 8bbd52b2c..000000000 --- a/lib/routing/src/validators/frontend/offer/offer-details-search-params-transform-schema.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { offerSchema } from '@echo/model/validators/offer-schema' -import { slugSchema } from '@echo/model/validators/slug-schema' -import { findIndex, isEmpty, isNil, propEq } from 'ramda' -import { object } from 'zod' - -export const offerDetailsSearchParamsTransformSchema = object({ - offers: offerSchema.array(), - searchParams: object({ - offer: slugSchema.optional() - }) -}).transform(({ offers, searchParams }) => { - if (isEmpty(searchParams) || isNil(searchParams.offer)) { - return undefined - } - const index = findIndex(propEq(searchParams.offer, 'slug'), offers) - if (index === -1) { - return undefined - } - return index -}) diff --git a/lib/routing/src/validators/frontend/swap/swap-details-query-params-schema.ts b/lib/routing/src/validators/frontend/swap/swap-details-query-params-schema.ts deleted file mode 100644 index 53ecebed8..000000000 --- a/lib/routing/src/validators/frontend/swap/swap-details-query-params-schema.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { withSlugSchema } from '@echo/model/validators/slug-schema' -import { object } from 'zod' - -export const swapDetailsQueryParamsSchema = object({ - swap: withSlugSchema -}) diff --git a/lib/routing/src/validators/frontend/swap/swap-details-search-params-schema.ts b/lib/routing/src/validators/frontend/swap/swap-details-search-params-schema.ts deleted file mode 100644 index cf3d5c2c6..000000000 --- a/lib/routing/src/validators/frontend/swap/swap-details-search-params-schema.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { serializeSwapSchema } from '@echo/model/validators/swap-schema' -import { object } from 'zod' - -export const swapDetailsSearchParamsSchema = object({ - swap: serializeSwapSchema -}).strict() diff --git a/lib/routing/src/validators/frontend/swap/swap-details-search-params-transform-schema.ts b/lib/routing/src/validators/frontend/swap/swap-details-search-params-transform-schema.ts deleted file mode 100644 index f16fd2319..000000000 --- a/lib/routing/src/validators/frontend/swap/swap-details-search-params-transform-schema.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { slugSchema } from '@echo/model/validators/slug-schema' -import { swapSchema } from '@echo/model/validators/swap-schema' -import { findIndex, isEmpty, isNil, propEq } from 'ramda' -import { object } from 'zod' - -export const swapDetailsSearchParamsTransformSchema = object({ - swaps: swapSchema.array(), - searchParams: object({ - swap: slugSchema.optional() - }) -}).transform(({ swaps, searchParams }) => { - if (isEmpty(searchParams) || isNil(searchParams.swap)) { - return undefined - } - const index = findIndex(propEq(searchParams.swap, 'slug'), swaps) - if (index === -1) { - return undefined - } - return index -}) diff --git a/lib/ui/src/components/base/navigation/panels/listings-panel.tsx b/lib/ui/src/components/base/navigation/panels/listings-panel.tsx index e2a4b7b56..9eba1f41a 100644 --- a/lib/ui/src/components/base/navigation/panels/listings-panel.tsx +++ b/lib/ui/src/components/base/navigation/panels/listings-panel.tsx @@ -1,37 +1,26 @@ 'use client' +import { frontendRoutes } from '@echo/routing/constants/frontend-routes' import { ListingCards } from '@echo/ui/components/listing/card/listing-cards' -import { ListingDetailsModal } from '@echo/ui/components/listing/details/listing-details-modal' import type { ListingWithRole } from '@echo/ui/types/listing-with-role' -import type { Nullable } from '@echo/utils/types/nullable' import { TabPanel } from '@headlessui/react' import { clsx } from 'clsx' -import { find, isNil, nth, pipe, propEq } from 'ramda' -import { type FunctionComponent, useState } from 'react' +import { useRouter } from 'next/navigation' +import { type FunctionComponent } from 'react' interface Props { listings: ListingWithRole[] - selection?: Nullable show?: boolean } -export const ListingsPanel: FunctionComponent = ({ listings, selection, show }) => { - const [listing, setListing] = useState>( - isNil(selection) ? undefined : nth(selection, listings) - ) +export const ListingsPanel: FunctionComponent = ({ listings, show }) => { + const router = useRouter() if (show) { return ( { - pipe(find(propEq(slug, 'slug')), setListing)(listings) - }} - /> - { - setListing(undefined) + router.push(frontendRoutes.listing.details.getUrl({ slug })) }} /> diff --git a/lib/ui/src/components/base/navigation/panels/offers-panel.tsx b/lib/ui/src/components/base/navigation/panels/offers-panel.tsx index 8b9669f20..bd8ee388a 100644 --- a/lib/ui/src/components/base/navigation/panels/offers-panel.tsx +++ b/lib/ui/src/components/base/navigation/panels/offers-panel.tsx @@ -1,24 +1,19 @@ 'use client' import { frontendRoutes } from '@echo/routing/constants/frontend-routes' import { OfferCards } from '@echo/ui/components/offer/card/offer-cards' -import { OfferDetailsModal } from '@echo/ui/components/offer/details/offer-details-modal' import type { OfferWithRole } from '@echo/ui/types/offer-with-role' -import type { Nullable } from '@echo/utils/types/nullable' import { TabPanel } from '@headlessui/react' import { clsx } from 'clsx' import { useRouter } from 'next/navigation' -import { find, isNil, nth, pipe, propEq } from 'ramda' -import { type FunctionComponent, useState } from 'react' +import { type FunctionComponent } from 'react' interface Props { offers: OfferWithRole[] - selection?: Nullable show?: boolean } -export const OffersPanel: FunctionComponent = ({ offers, selection, show }) => { +export const OffersPanel: FunctionComponent = ({ offers, show }) => { const router = useRouter() - const [offer, setOffer] = useState>(isNil(selection) ? undefined : nth(selection, offers)) if (show) { return ( @@ -26,23 +21,7 @@ export const OffersPanel: FunctionComponent = ({ offers, selection, show { - pipe(find(propEq(slug, 'slug')), setOffer)(offers) - }} - /> - { - // redirect the user to their profile so they can see their NFTs - router.push(frontendRoutes.user.profile.get()) - }} - onSwap={() => { - if (!isNil(offer)) { - router.push(frontendRoutes.swap.details.withQuery({ swap: offer }).get()) - } - }} - onUpdate={setOffer} - onClose={() => { - setOffer(undefined) + router.push(frontendRoutes.offer.details.getUrl({ slug })) }} /> diff --git a/lib/ui/src/components/base/navigation/panels/redeemable-offers-panel.tsx b/lib/ui/src/components/base/navigation/panels/redeemable-offers-panel.tsx index e7dc61a3d..3e9f9ecce 100644 --- a/lib/ui/src/components/base/navigation/panels/redeemable-offers-panel.tsx +++ b/lib/ui/src/components/base/navigation/panels/redeemable-offers-panel.tsx @@ -1,8 +1,6 @@ 'use client' - import { frontendRoutes } from '@echo/routing/constants/frontend-routes' import { OfferCards } from '@echo/ui/components/offer/card/offer-cards' -import { OfferDetailsModal } from '@echo/ui/components/offer/details/offer-details-modal' import { SWRKeys } from '@echo/ui/constants/swr-keys' import { useDependencies } from '@echo/ui/hooks/use-dependencies' import type { OfferWithRole } from '@echo/ui/types/offer-with-role' @@ -10,7 +8,7 @@ import type { Nullable } from '@echo/utils/types/nullable' import { TabPanel } from '@headlessui/react' import { clsx } from 'clsx' import { useRouter } from 'next/navigation' -import { find, isNil, nth, pipe, propEq } from 'ramda' +import { isNil, nth } from 'ramda' import { type FunctionComponent, useEffect, useState } from 'react' import useSWR from 'swr' @@ -62,22 +60,7 @@ export const RedeemableOffersPanel: FunctionComponent = ({ offers, select { - pipe(find(propEq(slug, 'slug')), setOffer)(filteredOffers) - }} - /> - { - router.push(frontendRoutes.user.profile.get()) - }} - onSwap={() => { - if (!isNil(offer)) { - router.push(frontendRoutes.swap.details.withQuery({ swap: offer }).get()) - } - }} - onUpdate={setOffer} - onClose={() => { - setOffer(undefined) + router.push(frontendRoutes.offer.details.getUrl({ slug })) }} /> diff --git a/lib/ui/src/components/base/navigation/panels/swaps-panel.tsx b/lib/ui/src/components/base/navigation/panels/swaps-panel.tsx index 9a9ffbd63..b2c178603 100644 --- a/lib/ui/src/components/base/navigation/panels/swaps-panel.tsx +++ b/lib/ui/src/components/base/navigation/panels/swaps-panel.tsx @@ -1,35 +1,27 @@ 'use client' +import { frontendRoutes } from '@echo/routing/constants/frontend-routes' import { SwapCards } from '@echo/ui/components/swap/card/swap-cards' -import { SwapDetailsModal } from '@echo/ui/components/swap/details/swap-details-modal' import type { SwapWithRole } from '@echo/ui/types/swap-with-role' -import type { Nullable } from '@echo/utils/types/nullable' import { TabPanel } from '@headlessui/react' import { clsx } from 'clsx' -import { find, isNil, nth, propEq } from 'ramda' -import { type FunctionComponent, useState } from 'react' +import { useRouter } from 'next/navigation' +import { type FunctionComponent } from 'react' interface Props { swaps: SwapWithRole[] - selection?: Nullable show?: boolean } -export const SwapsPanel: FunctionComponent = ({ swaps, selection, show }) => { - const [swap, setSwap] = useState>(isNil(selection) ? undefined : nth(selection, swaps)) - // TODO swap details +export const SwapsPanel: FunctionComponent = ({ swaps, show }) => { + const router = useRouter() + if (show) { return ( { - setSwap(find(propEq(slug, 'slug'), swaps)) - }} - /> - { - setSwap(undefined) + router.push(frontendRoutes.swap.details.getUrl({ slug })) }} /> diff --git a/lib/ui/src/components/listing/create/create-listing-manager.tsx b/lib/ui/src/components/listing/create/create-listing-manager.tsx index 3b11f5f03..596308fd4 100644 --- a/lib/ui/src/components/listing/create/create-listing-manager.tsx +++ b/lib/ui/src/components/listing/create/create-listing-manager.tsx @@ -39,9 +39,7 @@ export const CreateListingManager: FunctionComponent = ({ creator, creato target: target, expiration }) - router.replace( - frontendRoutes.listing.details.withQuery({ listing }).getUrl({ slug: listing.target.collection.slug }) - ) + router.replace(frontendRoutes.listing.details.getUrl({ slug: listing.slug })) } catch (err) { errorCallback({ alert: { severity: CalloutSeverity.Error, message: t('new') }, diff --git a/lib/ui/src/components/listing/create/create-listing.tsx b/lib/ui/src/components/listing/create/create-listing.tsx index 9e79637ba..0699d0798 100644 --- a/lib/ui/src/components/listing/create/create-listing.tsx +++ b/lib/ui/src/components/listing/create/create-listing.tsx @@ -8,8 +8,8 @@ import { CreateListingFirstStep } from '@echo/ui/components/listing/create/creat import { CreateListingReviewStep } from '@echo/ui/components/listing/create/create-listing-review-step' import { CreateTargetNextButton } from '@echo/ui/components/listing/create/create-target-next-button' import { CreateTradeBottomBar } from '@echo/ui/components/trade/create/create-trade-bottom-bar' -import { CreateTradeStepLayout } from '@echo/ui/components/trade/create/layout/create-trade-step-layout' import { CreateTradeStepIndicator } from '@echo/ui/components/trade/create/create-trade-step-indicator' +import { CreateTradeStepLayout } from '@echo/ui/components/trade/create/layout/create-trade-step-layout' import { ListingCreationSteps } from '@echo/ui/constants/listing-creation-steps' import { useNfts } from '@echo/ui/hooks/use-nfts' import type { Nullable } from '@echo/utils/types/nullable' @@ -51,10 +51,10 @@ export const CreateListing: FunctionComponent = ({ const [currentStep, setCurrentStep] = useState(0) const steps = values(ListingCreationSteps) const totalSteps = steps.length - const subtitles = [t('steps.collection'), t('steps.review'), t('steps.done')] + const subtitles = [t('steps.collection'), t('steps.review')] const handleNext = () => { - if (currentStep < totalSteps - 2) { + if (currentStep < totalSteps - 1) { setCurrentStep(currentStep + 1) } else { // FIXME Should not be undefined at this point @@ -101,7 +101,12 @@ export const CreateListing: FunctionComponent = ({ /> )} - + = ({ const loading = isCreateTargetNextButtonDisabled(creatorNfts, target, currentStep) const handleNext = () => { - if (currentStep < totalSteps - 2) { + if (currentStep < totalSteps - 1) { onNext() } else { onSuccess?.() @@ -36,7 +36,7 @@ export const CreateTargetNextButton: FunctionComponent = ({ } const getNextBtnLabel = () => { - if (currentStep < totalSteps - 2) { + if (currentStep < totalSteps - 1) { return t('nextBtn') } return t('createBtn') diff --git a/lib/ui/src/components/listing/details/listing-details-modal-body.tsx b/lib/ui/src/components/listing/details/listing-details-modal-body.tsx deleted file mode 100644 index 6a8bda0d7..000000000 --- a/lib/ui/src/components/listing/details/listing-details-modal-body.tsx +++ /dev/null @@ -1,21 +0,0 @@ -'use client' -import { DetailsModalBodyLayout } from '@echo/ui/components/base/layout/details-modal-body-layout' -import { ListingDetails } from '@echo/ui/components/listing/details/listing-details' -import type { ListingDetailsModalProps } from '@echo/ui/components/listing/details/listing-details-modal' -import { isNil } from 'ramda' -import type { FunctionComponent } from 'react' - -export const ListingDetailsModalBody: FunctionComponent = ({ - listing, - onUpdate, - onClose -}) => { - if (isNil(listing)) { - return null - } - return ( - - - - ) -} diff --git a/lib/ui/src/components/listing/details/listing-details-modal.tsx b/lib/ui/src/components/listing/details/listing-details-modal.tsx deleted file mode 100644 index b983103ad..000000000 --- a/lib/ui/src/components/listing/details/listing-details-modal.tsx +++ /dev/null @@ -1,21 +0,0 @@ -'use client' -import { Modal } from '@echo/ui/components/base/modal/modal' -import type { ListingDetailsProps } from '@echo/ui/components/listing/details/listing-details' -import { ListingDetailsModalBody } from '@echo/ui/components/listing/details/listing-details-modal-body' -import type { ListingWithRole } from '@echo/ui/types/listing-with-role' -import type { Nullable } from '@echo/utils/types/nullable' -import { isNil } from 'ramda' -import type { FunctionComponent } from 'react' - -export interface ListingDetailsModalProps extends Omit { - listing: Nullable - onClose?: VoidFunction -} - -export const ListingDetailsModal: FunctionComponent = ({ listing, onClose, onUpdate }) => { - return ( - - - - ) -} diff --git a/lib/ui/src/components/listing/details/listing-details.tsx b/lib/ui/src/components/listing/details/listing-details.tsx index 17c7037ee..11c1b6184 100644 --- a/lib/ui/src/components/listing/details/listing-details.tsx +++ b/lib/ui/src/components/listing/details/listing-details.tsx @@ -19,11 +19,9 @@ import { type FunctionComponent, useCallback, useState } from 'react' export interface ListingDetailsProps { listing: ListingWithRole - onUpdate?: (listing: ListingWithRole) => void - onClose?: VoidFunction } -export const ListingDetails: FunctionComponent = ({ listing, onUpdate, onClose }) => { +export const ListingDetails: FunctionComponent = ({ listing }) => { const t = useTranslations('error.listing') const router = useRouter() const [loading, setLoading] = useState(false) @@ -31,8 +29,8 @@ export const ListingDetails: FunctionComponent = ({ listing const onCancel = useCallback( async (slug: Lowercase) => { try { - const cancelledListing = await cancelListing(slug) - onUpdate?.(assoc('role', listing.role, cancelledListing)) + await cancelListing(slug) + router.push(frontendRoutes.user.profile.getUrl()) } catch (err) { errorCallback({ alert: { severity: CalloutSeverity.Error, message: t('cancel') }, @@ -42,7 +40,7 @@ export const ListingDetails: FunctionComponent = ({ listing setLoading(false) } }, - [cancelListing, listing, onUpdate, t] + [cancelListing, listing, router, t] ) const { target, creator, role } = listing const nfts = pipe(listingItems, nonEmptyMap(pipe(nftItemToNft(listing.creator), assoc('attributes', []))))(listing) @@ -55,7 +53,9 @@ export const ListingDetails: FunctionComponent = ({ listing { + router.back() + }} onCancel={(listing) => { setLoading(true) void onCancel(listing.slug) diff --git a/lib/ui/src/components/offer/create/create-offer-flow.tsx b/lib/ui/src/components/offer/create/create-offer-flow.tsx index bebf4fde9..dc60b851f 100644 --- a/lib/ui/src/components/offer/create/create-offer-flow.tsx +++ b/lib/ui/src/components/offer/create/create-offer-flow.tsx @@ -118,7 +118,7 @@ export const CreateOfferFlow: FunctionComponent = ({ receiverItems={receiverSelection.nfts} onNext={handleNext} onSuccess={(offer) => { - router.replace(frontendRoutes.offer.details.withQuery({ offer }).get({ username: sender.username })) + router.replace(frontendRoutes.offer.details.getUrl({ slug: offer.slug })) }} /> diff --git a/lib/ui/src/components/offer/details/offer-details-modal-body.tsx b/lib/ui/src/components/offer/details/offer-details-modal-body.tsx deleted file mode 100644 index f15aaccfe..000000000 --- a/lib/ui/src/components/offer/details/offer-details-modal-body.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client' -import { DetailsModalBodyLayout } from '@echo/ui/components/base/layout/details-modal-body-layout' -import { OfferDetails } from '@echo/ui/components/offer/details/offer-details' -import type { OfferDetailsModalProps } from '@echo/ui/components/offer/details/offer-details-modal' -import { isNil } from 'ramda' -import type { FunctionComponent } from 'react' - -export const OfferDetailsModalBody: FunctionComponent = ({ - offer, - onClose, - onRedeem, - onSwap, - onUpdate -}) => { - if (isNil(offer)) { - return null - } - return ( - - - - ) -} diff --git a/lib/ui/src/components/offer/details/offer-details-modal.tsx b/lib/ui/src/components/offer/details/offer-details-modal.tsx deleted file mode 100644 index 839519006..000000000 --- a/lib/ui/src/components/offer/details/offer-details-modal.tsx +++ /dev/null @@ -1,29 +0,0 @@ -'use client' -import { Modal } from '@echo/ui/components/base/modal/modal' -import { OfferDetailsModalBody } from '@echo/ui/components/offer/details/offer-details-modal-body' -import type { OfferWithRole } from '@echo/ui/types/offer-with-role' -import type { Nullable } from '@echo/utils/types/nullable' -import { isNil } from 'ramda' -import type { FunctionComponent } from 'react' - -export interface OfferDetailsModalProps { - offer: Nullable - onClose?: VoidFunction - onRedeem?: (offer: OfferWithRole) => void - onSwap?: VoidFunction - onUpdate?: (offer: OfferWithRole) => void -} - -export const OfferDetailsModal: FunctionComponent = ({ - offer, - onClose, - onRedeem, - onSwap, - onUpdate -}) => { - return ( - - - - ) -} diff --git a/lib/ui/src/components/offer/details/offer-details.tsx b/lib/ui/src/components/offer/details/offer-details.tsx index d0dcfb14d..a24e7716c 100644 --- a/lib/ui/src/components/offer/details/offer-details.tsx +++ b/lib/ui/src/components/offer/details/offer-details.tsx @@ -2,6 +2,7 @@ import { offerReceiverNftItems } from '@echo/model/helpers/offer/offer-receiver-nft-items' import { offerSenderNftItems } from '@echo/model/helpers/offer/offer-sender-nft-items' import { nftItemToNft } from '@echo/model/mappers/item/nft-item-to-nft' +import { frontendRoutes } from '@echo/routing/constants/frontend-routes' import { OfferDetailsBottomBar } from '@echo/ui/components/offer/details/offer-details-bottom-bar' import { OfferDetailsOfferState } from '@echo/ui/components/offer/details/offer-details-offer-state' import { TradeDetailsLayout } from '@echo/ui/components/trade/details/layout/trade-details-layout' @@ -9,19 +10,18 @@ import { TradeDetailsItems } from '@echo/ui/components/trade/details/trade-detai import type { OfferWithRole } from '@echo/ui/types/offer-with-role' import { nonEmptyMap } from '@echo/utils/helpers/non-empty-map' import { clsx } from 'clsx' +import { useRouter } from 'next/navigation' import { assoc, pipe } from 'ramda' import { type FunctionComponent, useState } from 'react' export interface OfferDetailsProps { offer: OfferWithRole - onClose?: VoidFunction - onRedeem?: (offer: OfferWithRole) => void - onSwap?: VoidFunction - onUpdate?: (offer: OfferWithRole) => void } -export const OfferDetails: FunctionComponent = ({ offer, onClose, onRedeem, onSwap, onUpdate }) => { +export const OfferDetails: FunctionComponent = ({ offer }) => { + const router = useRouter() const { sender, receiver } = offer + const [updatedOffer, setUpdatedOffer] = useState(offer) const [loading, setLoading] = useState(false) const receiverNfts = pipe( offerReceiverNftItems, @@ -33,7 +33,7 @@ export const OfferDetails: FunctionComponent = ({ offer, onCl )(offer) return ( - +
= ({ offer, onCl />
{ + router.back() + }} onError={() => { setLoading(false) }} onLoading={() => { setLoading(true) }} - onRedeem={onRedeem} - onSwap={onSwap} - onUpdate={onUpdate} + onRedeem={(offer) => { + setUpdatedOffer(offer) + setLoading(false) + }} + // TODO Not sure if that's the behaviour we want, but will work for now + onSwap={() => { + router.push(frontendRoutes.user.profile.getUrl()) + }} + onUpdate={(offer) => { + setUpdatedOffer(offer) + setLoading(false) + }} />
) diff --git a/lib/ui/src/components/swap/details/swap-details-modal-body.tsx b/lib/ui/src/components/swap/details/swap-details-modal-body.tsx deleted file mode 100644 index c9327d083..000000000 --- a/lib/ui/src/components/swap/details/swap-details-modal-body.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client' -import { DetailsModalBodyLayout } from '@echo/ui/components/base/layout/details-modal-body-layout' -import { SwapDetails } from '@echo/ui/components/swap/details/swap-details' -import type { SwapWithRole } from '@echo/ui/types/swap-with-role' -import type { Nullable } from '@echo/utils/types/nullable' -import { isNil } from 'ramda' -import type { FunctionComponent } from 'react' - -interface Props { - swap: Nullable - onClose?: VoidFunction -} - -export const SwapDetailsModalBody: FunctionComponent = ({ swap, onClose }) => { - if (isNil(swap)) { - return null - } - return ( - - - - ) -} diff --git a/lib/ui/src/components/swap/details/swap-details-modal.tsx b/lib/ui/src/components/swap/details/swap-details-modal.tsx deleted file mode 100644 index 89a79565d..000000000 --- a/lib/ui/src/components/swap/details/swap-details-modal.tsx +++ /dev/null @@ -1,20 +0,0 @@ -'use client' -import { Modal } from '@echo/ui/components/base/modal/modal' -import { SwapDetailsModalBody } from '@echo/ui/components/swap/details/swap-details-modal-body' -import type { SwapWithRole } from '@echo/ui/types/swap-with-role' -import type { Nullable } from '@echo/utils/types/nullable' -import { isNil } from 'ramda' -import type { FunctionComponent } from 'react' - -interface Props { - swap: Nullable - onClose?: VoidFunction -} - -export const SwapDetailsModal: FunctionComponent = ({ swap, onClose }) => { - return ( - - - - ) -} diff --git a/lib/ui/src/components/swap/details/swap-details.tsx b/lib/ui/src/components/swap/details/swap-details.tsx index 473b30e7c..338218035 100644 --- a/lib/ui/src/components/swap/details/swap-details.tsx +++ b/lib/ui/src/components/swap/details/swap-details.tsx @@ -8,15 +8,16 @@ import { TradeDetailsItems } from '@echo/ui/components/trade/details/trade-detai import type { SwapWithRole } from '@echo/ui/types/swap-with-role' import { nonEmptyMap } from '@echo/utils/helpers/non-empty-map' import { clsx } from 'clsx' +import { useRouter } from 'next/navigation' import { assoc, pipe } from 'ramda' import type { FunctionComponent } from 'react' export interface SwapDetailsProps { swap: SwapWithRole - onClose?: VoidFunction } -export const SwapDetails: FunctionComponent = ({ swap, onClose }) => { +export const SwapDetails: FunctionComponent = ({ swap }) => { + const router = useRouter() const { sender, receiver } = swap const receiverNfts = pipe( swapReceiverNftItems, @@ -38,7 +39,12 @@ export const SwapDetails: FunctionComponent = ({ swap, onClose role={swap.role} /> - + { + router.back() + }} + /> ) } diff --git a/lib/ui/src/pages/collection/collection-navigation.tsx b/lib/ui/src/pages/collection/collection-navigation.tsx index b00cbf07f..91d503496 100644 --- a/lib/ui/src/pages/collection/collection-navigation.tsx +++ b/lib/ui/src/pages/collection/collection-navigation.tsx @@ -15,7 +15,7 @@ import type { SwapWithRole } from '@echo/ui/types/swap-with-role' import type { TabOptions } from '@echo/ui/types/tab-options' import { isFalsy } from '@echo/utils/helpers/is-falsy' import { TabGroup, TabList, TabPanels } from '@headlessui/react' -import { all, always, filter, find, findIndex, ifElse, isEmpty, isNil, map, pipe, prop, propEq } from 'ramda' +import { all, always, find, ifElse, isEmpty, isNil, map, pipe, prop, propEq } from 'ramda' import type { FunctionComponent } from 'react' type TabName = 'items' | 'listings' | 'offers' | 'swaps' @@ -26,17 +26,9 @@ interface Props { nfts: OwnedNft[] offers: OfferWithRole[] swaps: SwapWithRole[] - selection?: number } -export const CollectionNavigation: FunctionComponent = ({ - collection, - listings, - nfts, - offers, - swaps, - selection -}) => { +export const CollectionNavigation: FunctionComponent = ({ collection, listings, nfts, offers, swaps }) => { const tabs: TabOptions[] = [ { name: 'items', @@ -59,13 +51,6 @@ export const CollectionNavigation: FunctionComponent = ({ show: !isEmpty(swaps) } ] - function tabGroupProps() { - if (isNil(selection)) { - return {} - } - const defaultIndex = pipe(filter(propEq(true, 'show')), findIndex(propEq('listings', 'name')))(tabs) - return { defaultIndex } - } function showTab(name: TabName) { return pipe(find>(propEq(name, 'name')), ifElse(isNil, always(false), prop('show')))(tabs) } @@ -74,7 +59,7 @@ export const CollectionNavigation: FunctionComponent = ({ return null } return ( - + @@ -83,7 +68,7 @@ export const CollectionNavigation: FunctionComponent = ({ - + diff --git a/lib/ui/src/pages/collection/collection-page.tsx b/lib/ui/src/pages/collection/collection-page.tsx index 5a1f05e26..0b9a6e6a4 100644 --- a/lib/ui/src/pages/collection/collection-page.tsx +++ b/lib/ui/src/pages/collection/collection-page.tsx @@ -19,32 +19,16 @@ interface Props { nfts: OwnedNft[] offers: OfferWithRole[] swaps: SwapWithRole[] - selection?: number } -export const CollectionPage: FunctionComponent = ({ - collection, - counts, - listings, - nfts, - offers, - selection, - swaps -}) => { +export const CollectionPage: FunctionComponent = ({ collection, counts, listings, nfts, offers, swaps }) => { return ( - + ) diff --git a/lib/ui/src/pages/home/swap/recent-swaps.tsx b/lib/ui/src/pages/home/swap/recent-swaps.tsx index 0e187d933..3214b0fb8 100644 --- a/lib/ui/src/pages/home/swap/recent-swaps.tsx +++ b/lib/ui/src/pages/home/swap/recent-swaps.tsx @@ -1,31 +1,30 @@ 'use client' +import { frontendRoutes } from '@echo/routing/constants/frontend-routes' import { SwapCards } from '@echo/ui/components/swap/card/swap-cards' -import { SwapDetailsModal } from '@echo/ui/components/swap/details/swap-details-modal' import { HomeSectionLayout } from '@echo/ui/pages/home/layout/home-section-layout' import type { SwapWithRole } from '@echo/ui/types/swap-with-role' -import type { Nullable } from '@echo/utils/types/nullable' import { useTranslations } from 'next-intl' +import { useRouter } from 'next/navigation' import { isEmpty } from 'ramda' -import { type FunctionComponent, useState } from 'react' +import { type FunctionComponent } from 'react' interface Props { swaps: SwapWithRole[] } export const RecentSwaps: FunctionComponent = ({ swaps }) => { + const router = useRouter() const t = useTranslations('home.recentSwaps') - const [swap, setSwap] = useState>(undefined) if (isEmpty(swaps)) { return null } return ( - - { - setSwap(undefined) + { + router.push(frontendRoutes.swap.details.getUrl({ slug })) }} /> diff --git a/lib/ui/src/pages/profile/profile-navigation.tsx b/lib/ui/src/pages/profile/profile-navigation.tsx index 9228bd0f8..45be71541 100644 --- a/lib/ui/src/pages/profile/profile-navigation.tsx +++ b/lib/ui/src/pages/profile/profile-navigation.tsx @@ -17,7 +17,7 @@ import type { SwapWithRole } from '@echo/ui/types/swap-with-role' import type { TabOptions } from '@echo/ui/types/tab-options' import { isFalsy } from '@echo/utils/helpers/is-falsy' import { TabGroup, TabList, TabPanels } from '@headlessui/react' -import { all, always, filter, find, findIndex, ifElse, isEmpty, isNil, map, pipe, prop, propEq } from 'ramda' +import { all, always, find, ifElse, isEmpty, isNil, map, pipe, prop, propEq } from 'ramda' import type { FunctionComponent } from 'react' type TabName = 'items' | 'listings' | 'offers' | 'swaps' | 'explore' | 'redeemable' @@ -29,7 +29,6 @@ interface Props { pendingListings: ListingWithRole[] swaps: SwapWithRole[] redeemableOffers: OfferWithRole[] - selection?: number } export const ProfileNavigation: FunctionComponent = ({ @@ -38,8 +37,7 @@ export const ProfileNavigation: FunctionComponent = ({ offers, pendingListings, swaps, - redeemableOffers, - selection + redeemableOffers }) => { const tabs: TabOptions[] = [ { @@ -77,16 +75,8 @@ export const ProfileNavigation: FunctionComponent = ({ return null } - function tabGroupProps() { - if (isNil(selection)) { - return {} - } - const defaultIndex = pipe(filter(propEq(true, 'show')), findIndex(propEq('swaps', 'name')))(tabs) - return { defaultIndex } - } - return ( - + @@ -99,7 +89,7 @@ export const ProfileNavigation: FunctionComponent = ({ - + diff --git a/lib/ui/src/pages/profile/profile-page.tsx b/lib/ui/src/pages/profile/profile-page.tsx index 47b132b07..9c83f0d12 100644 --- a/lib/ui/src/pages/profile/profile-page.tsx +++ b/lib/ui/src/pages/profile/profile-page.tsx @@ -24,7 +24,6 @@ interface Props { swaps: SwapWithRole[] redeemableOffers: OfferWithRole[] user: User - selection?: number } export const ProfilePage: FunctionComponent = ({ @@ -35,8 +34,7 @@ export const ProfilePage: FunctionComponent = ({ pendingListings, swaps, redeemableOffers, - user, - selection + user }) => { return ( @@ -54,7 +52,6 @@ export const ProfilePage: FunctionComponent = ({ pendingListings={pendingListings} redeemableOffers={redeemableOffers} swaps={swaps} - selection={selection} /> diff --git a/lib/ui/src/pages/user/user-navigation.tsx b/lib/ui/src/pages/user/user-navigation.tsx index db981bfa9..e6c3283da 100644 --- a/lib/ui/src/pages/user/user-navigation.tsx +++ b/lib/ui/src/pages/user/user-navigation.tsx @@ -15,7 +15,7 @@ import type { SwapWithRole } from '@echo/ui/types/swap-with-role' import type { TabOptions } from '@echo/ui/types/tab-options' import { isFalsy } from '@echo/utils/helpers/is-falsy' import { TabGroup, TabList, TabPanels } from '@headlessui/react' -import { all, always, filter, find, findIndex, ifElse, isEmpty, isNil, map, pipe, prop, propEq } from 'ramda' +import { all, always, find, ifElse, isEmpty, isNil, map, pipe, prop, propEq } from 'ramda' import type { FunctionComponent } from 'react' type TabName = 'items' | 'listings' | 'offers' | 'swaps' @@ -26,10 +26,9 @@ interface Props { nfts: OwnedNft[] offers: OfferWithRole[] swaps: SwapWithRole[] - selection?: number } -export const UserNavigation: FunctionComponent = ({ isAuthUser, listings, nfts, offers, swaps, selection }) => { +export const UserNavigation: FunctionComponent = ({ isAuthUser, listings, nfts, offers, swaps }) => { const tabs: TabOptions[] = [ { name: 'items', @@ -49,14 +48,6 @@ export const UserNavigation: FunctionComponent = ({ isAuthUser, listings, } ] - function tabGroupProps() { - if (isNil(selection)) { - return {} - } - const defaultIndex = pipe(filter(propEq(true, 'show')), findIndex(propEq('offers', 'name')))(tabs) - return { defaultIndex } - } - function showTab(name: TabName) { return pipe(find>(propEq(name, 'name')), ifElse(isNil, always(false), prop('show')))(tabs) } @@ -67,7 +58,7 @@ export const UserNavigation: FunctionComponent = ({ isAuthUser, listings, } return ( - + @@ -77,7 +68,7 @@ export const UserNavigation: FunctionComponent = ({ isAuthUser, listings, - + diff --git a/lib/ui/src/pages/user/user-page.tsx b/lib/ui/src/pages/user/user-page.tsx index 2b6755c60..d3633ce19 100644 --- a/lib/ui/src/pages/user/user-page.tsx +++ b/lib/ui/src/pages/user/user-page.tsx @@ -19,33 +19,16 @@ interface Props { offers: OfferWithRole[] swaps: SwapWithRole[] user: User - selection?: number } -export const UserPage: FunctionComponent = ({ - isAuthUser, - counts, - listings, - nfts, - offers, - swaps, - user, - selection -}) => { +export const UserPage: FunctionComponent = ({ isAuthUser, counts, listings, nfts, offers, swaps, user }) => { return ( - + )