From d32eb2e7ed91f0c968469e63ca6d860f00f4563f Mon Sep 17 00:00:00 2001 From: Ardeman Date: Tue, 18 Mar 2025 16:42:18 +0800 Subject: [PATCH] feat: implement logging for ad interactions with new API and update banner component --- app/apis/news/create-log-ads.ts | 30 +++++++++++++++++++ app/layouts/news/banner.tsx | 23 ++++++++------- app/routes/actions.log.ads.$id.ts | 48 +++++++++++++++++++++++++++++++ app/routes/actions.subscribe.ts | 8 ++---- 4 files changed, 93 insertions(+), 16 deletions(-) create mode 100644 app/apis/news/create-log-ads.ts create mode 100644 app/routes/actions.log.ads.$id.ts diff --git a/app/apis/news/create-log-ads.ts b/app/apis/news/create-log-ads.ts new file mode 100644 index 0000000..359772e --- /dev/null +++ b/app/apis/news/create-log-ads.ts @@ -0,0 +1,30 @@ +import { z } from 'zod' + +import { HttpServer, type THttpServer } from '~/libs/http-server' +import type { TAdsSchema } from '~/pages/form-advertisements' + +const logAdsResponseSchema = z.object({ + data: z.object({ + Message: z.string(), + }), +}) +type TParameters = { + id: TAdsSchema['id'] +} & THttpServer + +export const createLogAdsRequest = async (parameters: TParameters) => { + const { id, ...restParameters } = parameters + const payload = { + ads_id: id, + } + try { + const { data } = await HttpServer(restParameters).post( + '/api/logs/ads', + payload, + ) + return logAdsResponseSchema.parse(data) + } catch (error) { + // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject + return Promise.reject(error) + } +} diff --git a/app/layouts/news/banner.tsx b/app/layouts/news/banner.tsx index 326a3b1..c7d4600 100644 --- a/app/layouts/news/banner.tsx +++ b/app/layouts/news/banner.tsx @@ -1,6 +1,7 @@ +import { Button } from '@headlessui/react' import Autoplay from 'embla-carousel-autoplay' import useEmblaCarousel from 'embla-carousel-react' -import { Link, useRouteLoaderData } from 'react-router' +import { useFetcher, useRouteLoaderData } from 'react-router' import type { loader } from '~/routes/_news' @@ -8,6 +9,7 @@ export const Banner = () => { const loaderData = useRouteLoaderData('routes/_news') const { adsData } = loaderData || {} const [emblaReference] = useEmblaCarousel({ loop: true }, [Autoplay()]) + const fetcher = useFetcher() return (
@@ -17,24 +19,25 @@ export const Banner = () => { ref={emblaReference} >
- {adsData?.map(({ image_url: urlImage, url: link, id }, index) => ( -
( + - window.open(url, '_blank')} > {id} - -
+ + ))}
diff --git a/app/routes/actions.log.ads.$id.ts b/app/routes/actions.log.ads.$id.ts new file mode 100644 index 0000000..c88fe2e --- /dev/null +++ b/app/routes/actions.log.ads.$id.ts @@ -0,0 +1,48 @@ +import { data } from 'react-router' +import { XiorError } from 'xior' + +import { createLogAdsRequest } from '~/apis/news/create-log-ads' +import { handleCookie } from '~/libs/cookies' + +import type { Route } from './+types/actions.log.ads.$id' + +export const action = async ({ request, params }: Route.ActionArgs) => { + const { userToken: accessToken } = await handleCookie(request) + const { id } = params + try { + const { data: logsData } = await createLogAdsRequest({ + id, + accessToken, + }) + + return data( + { + success: true, + logsData, + }, + { + status: 200, + statusText: 'OK', + }, + ) + } catch (error) { + if (error instanceof XiorError) { + return data( + { + success: false, + message: error?.response?.data?.error?.message || error.message, + }, + { + status: error?.response?.status || 500, + }, + ) + } + return data( + { + success: false, + message: 'Internal server error', + }, + { status: 500 }, + ) + } +} diff --git a/app/routes/actions.subscribe.ts b/app/routes/actions.subscribe.ts index 370e1d6..4f23446 100644 --- a/app/routes/actions.subscribe.ts +++ b/app/routes/actions.subscribe.ts @@ -4,7 +4,6 @@ import { getValidatedFormData } from 'remix-hook-form' import { XiorError } from 'xior' import { updateSubscribeRequest } from '~/apis/admin/update-subscribe' -import { getUser } from '~/apis/news/get-user' import { subscribeSchema, type TSubscribeSchema, @@ -34,18 +33,15 @@ export const action = async ({ request }: Route.ActionArgs) => { console.log('payload', payload) // eslint-disable-line no-console // TODO: will run after payment success - const { data: updateSubscribeData } = await updateSubscribeRequest({ + const { data: subscribeData } = await updateSubscribeRequest({ payload, accessToken, }) - console.log(updateSubscribeData) // eslint-disable-line no-console - - const { data: userData } = await getUser({ accessToken }) return data( { success: true, - user: userData, + subscribeData, }, { status: 200,