feat: implement logout action

This commit is contained in:
Ardeman 2025-02-27 23:50:46 +08:00
parent 5acf3970a3
commit 7db38d3b67
8 changed files with 70 additions and 19 deletions

View File

@ -42,7 +42,7 @@ export const PopupModal = ({
<DialogTitle className="relative flex justify-center"> <DialogTitle className="relative flex justify-center">
<button <button
onClick={onClose} onClick={onClose}
className="absolute top-0 left-0 items-center lg:hidden" className="absolute top-0 left-0 items-center sm:hidden"
> >
<LeftArrow <LeftArrow
width={50} width={50}

View File

@ -54,7 +54,7 @@ export const SuccessModal = ({ isOpen, onClose }: ModalProperties) => {
<DialogTitle className="relative flex justify-center"> <DialogTitle className="relative flex justify-center">
<button <button
onClick={onClose} onClick={onClose}
className="absolute top-0 left-0 items-center lg:hidden" className="absolute top-0 left-0 items-center sm:hidden"
> >
<LeftArrow <LeftArrow
width={50} width={50}

View File

@ -4,7 +4,7 @@ import { APP } from '~/configs/meta'
export const Banner = () => { export const Banner = () => {
return ( return (
<div className="min-h-[65px] lg:mx-10"> <div className="min-h-[65px] sm:mx-10">
<div className="relative"> <div className="relative">
<Link <Link
to="/#" to="/#"

View File

@ -115,7 +115,7 @@ export const Carousel = (properties: TNews) => {
<div> <div>
<h3 <h3
className={twMerge( className={twMerge(
'mt-2 w-full font-bold lg:mt-0', 'mt-2 w-full font-bold sm:mt-0',
type === 'hero' type === 'hero'
? 'text-2xl sm:text-4xl' ? 'text-2xl sm:text-4xl'
: 'text-xl sm:text-2xl', : 'text-xl sm:text-2xl',

View File

@ -1,4 +1,4 @@
import { Link, useRouteLoaderData } from 'react-router' import { Link, useFetcher, useRouteLoaderData } from 'react-router'
import { Button } from '~/components/ui/button' import { Button } from '~/components/ui/button'
import { APP } from '~/configs/meta' import { APP } from '~/configs/meta'
@ -8,6 +8,7 @@ import type { loader } from '~/routes/_layout.news'
export const HeaderTop = () => { export const HeaderTop = () => {
const { setIsLoginOpen } = useNewsContext() const { setIsLoginOpen } = useNewsContext()
const loaderData = useRouteLoaderData<typeof loader>('routes/_layout.news') const loaderData = useRouteLoaderData<typeof loader>('routes/_layout.news')
const fetcher = useFetcher()
return ( return (
<> <>
@ -29,13 +30,28 @@ export const HeaderTop = () => {
<Button className="h-8 w-auto rounded-none px-3 text-xs sm:h-[50px] sm:w-[150px] sm:text-lg"> <Button className="h-8 w-auto rounded-none px-3 text-xs sm:h-[50px] sm:w-[150px] sm:text-lg">
About Us About Us
</Button> </Button>
<Button {loaderData?.userToken ? (
variant="newsSecondary" <fetcher.Form
className="hidden sm:block" method="POST"
onClick={() => setIsLoginOpen(true)} action="/actions/news/logout"
> >
{loaderData?.userToken ? 'Logout' : 'Masuk'} <Button
</Button> variant="newsSecondary"
className="hidden sm:block"
type="submit"
>
Logout
</Button>
</fetcher.Form>
) : (
<Button
variant="newsSecondary"
className="hidden sm:block"
onClick={() => setIsLoginOpen(true)}
>
Masuk
</Button>
)}
</div> </div>
</div> </div>
</> </>

View File

@ -11,7 +11,7 @@ export const NewsPage = () => {
<Carousel {...SPOTLIGHT} /> <Carousel {...SPOTLIGHT} />
</Card> </Card>
<div className="min-h-[400px] sm:min-h-[300px]"> <div className="min-h-[400px] sm:min-h-[300px]">
<Newsletter className="mr-0 lg:-ml-14" /> <Newsletter className="mr-0 sm:-ml-14" />
</div> </div>
<Card> <Card>
<Carousel {...BERITA} /> <Carousel {...BERITA} />

View File

@ -6,6 +6,7 @@ import {
Outlet, Outlet,
Scripts, Scripts,
ScrollRestoration, ScrollRestoration,
type ShouldRevalidateFunctionArgs,
} from 'react-router' } from 'react-router'
import type { Route } from './+types/root' import type { Route } from './+types/root'
@ -36,7 +37,17 @@ export const meta = ({ location }: Route.MetaArgs) => {
] ]
} }
export function Layout({ children }: { children: ReactNode }) { export const shouldRevalidate = ({
actionResult,
defaultShouldRevalidate,
}: ShouldRevalidateFunctionArgs) => {
if (actionResult?.success) {
return true
}
return defaultShouldRevalidate
}
export const Layout = ({ children }: { children: ReactNode }) => {
return ( return (
<html lang="en"> <html lang="en">
<head> <head>
@ -57,11 +68,7 @@ export function Layout({ children }: { children: ReactNode }) {
) )
} }
export default function App() { export const ErrorBoundary = ({ error }: Route.ErrorBoundaryProps) => {
return <Outlet />
}
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
let message = 'Oops!' let message = 'Oops!'
let details = 'An unexpected error occurred.' let details = 'An unexpected error occurred.'
let stack: string | undefined let stack: string | undefined
@ -89,3 +96,9 @@ export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
</main> </main>
) )
} }
const App = () => {
return <Outlet />
}
export default App

View File

@ -0,0 +1,22 @@
import { data } from 'react-router'
import { setUserLogoutHeaders } from '~/libs/logout-header.server'
export const action = async () => {
try {
const responseHeaders = setUserLogoutHeaders()
return data(
{ success: true },
{ headers: responseHeaders, status: 200, statusText: 'OK' },
)
} catch {
return data(
{
message: 'Something went wrong',
success: false,
},
{ status: 500 },
)
}
}