Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

detailPage #128

Merged
merged 9 commits into from
Dec 11, 2024
18 changes: 13 additions & 5 deletions src/routeTree.gen.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/* prettier-ignore-start */

/* eslint-disable */

// @ts-nocheck

// noinspection JSUnusedGlobalSymbols

// This file is auto-generated by TanStack Router
// This file was automatically generated by TanStack Router.
// You should NOT make any changes in this file as it will be overwritten.
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.

// Import Routes

Expand All @@ -25,51 +25,61 @@ import { Route as EventsEventIdImport } from './routes/events/$eventId'
// Create/Update Routes

const LoginRoute = LoginImport.update({
id: '/login',
path: '/login',
getParentRoute: () => rootRoute,
} as any)

const IndexRoute = IndexImport.update({
id: '/',
path: '/',
getParentRoute: () => rootRoute,
} as any)

const SalesIndexRoute = SalesIndexImport.update({
id: '/sales/',
path: '/sales/',
getParentRoute: () => rootRoute,
} as any)

const MapIndexRoute = MapIndexImport.update({
id: '/map/',
path: '/map/',
getParentRoute: () => rootRoute,
} as any)

const EventsIndexRoute = EventsIndexImport.update({
id: '/events/',
path: '/events/',
getParentRoute: () => rootRoute,
} as any)

const DinnerIndexRoute = DinnerIndexImport.update({
id: '/dinner/',
path: '/dinner/',
getParentRoute: () => rootRoute,
} as any)

const CalendarIndexRoute = CalendarIndexImport.update({
id: '/calendar/',
path: '/calendar/',
getParentRoute: () => rootRoute,
} as any)

const HomeInfoCardRoute = HomeInfoCardImport.update({
id: '/home/infoCard',
path: '/home/infoCard',
getParentRoute: () => rootRoute,
} as any)

const EventsCreateRoute = EventsCreateImport.update({
id: '/events/create',
path: '/events/create',
getParentRoute: () => rootRoute,
} as any)

const EventsEventIdRoute = EventsEventIdImport.update({
id: '/events/$eventId',
path: '/events/$eventId',
getParentRoute: () => rootRoute,
} as any)
Expand Down Expand Up @@ -263,8 +273,6 @@ export const routeTree = rootRoute
._addFileChildren(rootRouteChildren)
._addFileTypes<FileRouteTypes>()

/* prettier-ignore-end */

/* ROUTE_MANIFEST_START
{
"routes": {
Expand Down
253 changes: 249 additions & 4 deletions src/routes/events/$eventId.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { createFileRoute } from '@tanstack/react-router';
import { useState } from 'react';
import { Header } from '../../components';
import { supabase } from '../../utils/supabase';

export const Route = createFileRoute('/events/$eventId')({
Expand All @@ -18,13 +20,256 @@ export const Route = createFileRoute('/events/$eventId')({
component: EventDetails
})

const styles = {
body:{
backgroundColor:'#3E3E3E'
},
container:{
flex: 1,
backgroundColor: '#FFFFFF'
},
card:{
borderRadius: "15px",
backgroundColor:'#FFFFFF',
margin: "1rem 1.5rem",
padding: "1rem"
},
icon:{
margin:"0.5rem"
},
}

function EventDetails() {
const { event } = Route.useLoaderData()
const [join, setJoin] = useState(false)
return (
<div>
<div>Event ID: {event.id}</div>
<div>Event Name: {event.name}</div>
<div>Event Description: {event.description}</div>
// <div style={styles.body}>
<div className="container mx-auto">
<Header />
<div className='bg-gray-800'>
{/* 不確定why不設置position就會蓋住header */}

{/* 圖片 */}
{/* 之後改用map */}
<div className='relative'>
<div className="carousel w-full">
<div id="item1" className="carousel-item w-full">
<img src="https://i.pinimg.com/originals/68/21/7d/68217da82cbeb3cc833ed2acdea7c738.gif" className="w-full" />
</div>
<div id="item2" className="carousel-item w-full">
<img src="https://i.pinimg.com/originals/79/de/27/79de27bafeb77f608ef74b3d02e727ba.gif"className="w-full" />
</div>
<div id="item3" className="carousel-item w-full">
<img src="https://i.pinimg.com/originals/df/f2/75/dff275ddc4aea5548575fd78d218965d.gif" className="w-full" />
</div>
<div id="item4" className="carousel-item w-full">
<img src="https://i.pinimg.com/originals/fc/b4/ee/fcb4ee6e201ec8f0de461a9f1ac65d2e.gif" className="w-full" />
</div>
</div>
{/* 換頁點點-要根據使用者提供的張數更改個數 */}
<div className="absolute bottom-11 flex w-full justify-center gap-2">
<a href="#item1" className="btn btn-xs">1</a>
<a href="#item2" className="btn btn-xs">2</a>
<a href="#item3" className="btn btn-xs">3</a>
<a href="#item4" className="btn btn-xs">4</a>
</div>
</div>

<div className='-translate-y-12'>

{/* 活動資訊 */}
<div className='static relative' style={styles.card}>
{/* 活動名稱 */}
<div className='flex place-content-between'>
<h1 className='text-xl m-1 font-bold'>{event.name}</h1>
{/* 收藏 */}
<div>
<label className='swap'>
<input type="checkbox" />
<svg style={styles.icon} className="swap-off w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12.01 6.001C6.5 1 1 8 5.782 13.001L12.011 20l6.23-7C23 8 17.5 1 12.01 6.002Z"/>
</svg>
<svg style={styles.icon} className="swap-on w-6 h-6 text-red-500 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
<path d="m12.75 20.66 6.184-7.098c2.677-2.884 2.559-6.506.754-8.705-.898-1.095-2.206-1.816-3.72-1.855-1.293-.034-2.652.43-3.963 1.442-1.315-1.012-2.678-1.476-3.973-1.442-1.515.04-2.825.76-3.724 1.855-1.806 2.201-1.915 5.823.772 8.706l6.183 7.097c.19.216.46.34.743.34a.985.985 0 0 0 .743-.34Z"/>
</svg>
</label>
</div>
</div>
{/* 時間 */}
<div className='flex p-2 items-center'>
<svg style={styles.icon} className="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/>
</svg>
<p>{event.start_time}~{event.end_time}</p>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle timezone display in event times

The direct display of start_time and end_time might show incorrect timezone information as mentioned in the PR objectives.

Consider using a date formatting library like date-fns or luxon to properly format the times:

-<p>{event.start_time}~{event.end_time}</p>
+<p>{format(parseISO(event.start_time), 'PPp')} ~ {format(parseISO(event.end_time), 'PPp')}</p>

Committable suggestion skipped: line range outside the PR's diff.

</div>
{/* 活動地點 */}
<div className='flex p-2 items-center'>
<svg style={styles.icon} className="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 13a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z"/>
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.8 13.938h-.011a7 7 0 1 0-11.464.144h-.016l.14.171c.1.127.2.251.3.371L12 21l5.13-6.248c.194-.209.374-.429.54-.659l.13-.155Z"/>
</svg>
</div>
{/* 活動價格 */}
<div className='flex p-2 items-center'>

<svg style={styles.icon} className="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 17.345a4.76 4.76 0 0 0 2.558 1.618c2.274.589 4.512-.446 4.999-2.31.487-1.866-1.273-3.9-3.546-4.49-2.273-.59-4.034-2.623-3.547-4.488.486-1.865 2.724-2.899 4.998-2.31.982.236 1.87.793 2.538 1.592m-3.879 12.171V21m0-18v2.2"/>
</svg>
<p>活動價格</p>

</div>
<button className="btn absolute bottom-1 right-1"
onClick={() => {
if (join) {
(document.getElementById("cancel_modal") as HTMLFormElement).showModal();
} else {
(document.getElementById("join_modal") as HTMLFormElement).showModal();
}
}}>
{join ? "已報名" : "報名活動"}
</button>

<dialog id="join_modal" className="modal">
<div className="modal-box w-11/12 max-w-5xl">
<h3 className="text-xl flex items-center justify-center">
<svg className="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5.365V3m0 2.365a5.338 5.338 0 0 1 5.133 5.368v1.8c0 2.386 1.867 2.982 1.867 4.175 0 .593 0 1.292-.538 1.292H5.538C5 18 5 17.301 5 16.708c0-1.193 1.867-1.789 1.867-4.175v-1.8A5.338 5.338 0 0 1 12 5.365ZM8.733 18c.094.852.306 1.54.944 2.112a3.48 3.48 0 0 0 4.646 0c.638-.572 1.236-1.26 1.33-2.112h-6.92Z"/>
</svg>
</h3>
<p className="py-4 text-xl flex items-center justify-center">確定要報名此活動嗎?</p>
<div className="modal-action justify-between">
<button className="btn w-1/2"
onClick={()=>{
setJoin(true);
if(document){
(document.getElementById('joinSuccess_modal') as HTMLFormElement).showModal();
(document.getElementById("join_modal") as HTMLFormElement).close();
}}}
>好</button>
<dialog id="joinSuccess_modal" className="modal">
<div className="modal-box w-11/12 max-w-5xl">
<div className='flex item-center justify-center'>
<svg className="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5.365V3m0 2.365a5.338 5.338 0 0 1 5.133 5.368v1.8c0 2.386 1.867 2.982 1.867 4.175 0 .593 0 1.292-.538 1.292H5.538C5 18 5 17.301 5 16.708c0-1.193 1.867-1.789 1.867-4.175v-1.8A5.338 5.338 0 0 1 12 5.365ZM8.733 18c.094.852.306 1.54.944 2.112a3.48 3.48 0 0 0 4.646 0c.638-.572 1.236-1.26 1.33-2.112h-6.92Z"/>
</svg>
<h3 className="font-bold text-lg">通知</h3>
</div>
<p className="py-4 flex item-center justify-center">活動報名成功!</p>
<div className="modal-action">
<form method="dialog" className='w-full'>
<button className="btn w-full">好</button>
</form>
</div>
</div>
</dialog>
<form method="dialog" className='w-1/2'>
<button className="btn w-full">取消</button>
</form>
</div>
</div>
</dialog>
<dialog id="cancel_modal" className="modal">
<div className="modal-box w-11/12 max-w-5xl">
<div>
<svg className="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5.365V3m0 2.365a5.338 5.338 0 0 1 5.133 5.368v1.8c0 2.386 1.867 2.982 1.867 4.175 0 .593 0 1.292-.538 1.292H5.538C5 18 5 17.301 5 16.708c0-1.193 1.867-1.789 1.867-4.175v-1.8A5.338 5.338 0 0 1 12 5.365ZM8.733 18c.094.852.306 1.54.944 2.112a3.48 3.48 0 0 0 4.646 0c.638-.572 1.236-1.26 1.33-2.112h-6.92Z"/>
</svg>
<h3 className="text-xl flex items-center justify-center">確定要取消報名此活動嗎?</h3>
</div>
<div className="modal-action justify-between">
<button
className="btn w-1/2"
onClick={() => {
setJoin(false);
(document.getElementById("cancel_modal") as HTMLFormElement).close();
(document.getElementById("cancelSuccess_modal") as HTMLFormElement).showModal();
}}
>
</button>
<dialog id="cancelSuccess_modal" className="modal">
<div className="modal-box w-11/12 max-w-5xl">
<div className='flex item-center justify-center'>
<svg className="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5.365V3m0 2.365a5.338 5.338 0 0 1 5.133 5.368v1.8c0 2.386 1.867 2.982 1.867 4.175 0 .593 0 1.292-.538 1.292H5.538C5 18 5 17.301 5 16.708c0-1.193 1.867-1.789 1.867-4.175v-1.8A5.338 5.338 0 0 1 12 5.365ZM8.733 18c.094.852.306 1.54.944 2.112a3.48 3.48 0 0 0 4.646 0c.638-.572 1.236-1.26 1.33-2.112h-6.92Z"/>
</svg>
<h3 className="font-bold text-lg">通知</h3>
</div>
<p className="py-4 flex item-center justify-center">活動取消報名成功!</p>
<div className="modal-action">
<form method="dialog" className='w-full'>
<button className="btn w-full">好</button>
</form>
</div>
</div>
</dialog>
<form method="dialog" className="w-1/2">
<button className="btn w-full">取消</button>
</form>
</div>
</div>
</dialog>
Comment on lines +121 to +211
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve modal implementation and error handling

The current modal implementation has several areas for improvement:

  1. TypeScript assertions could be avoided with proper typing
  2. Similar modal structures could be extracted into a reusable component
  3. Missing error handling for registration actions

Consider creating a reusable modal component:

type ModalProps = {
  id: string;
  title: string;
  message: string;
  onConfirm: () => Promise<void>;
  onCancel: () => void;
};

const ConfirmationModal: React.FC<ModalProps> = ({
  id,
  title,
  message,
  onConfirm,
  onCancel,
}) => {
  const [error, setError] = useState<string | null>(null);
  
  const handleConfirm = async () => {
    try {
      await onConfirm();
    } catch (err) {
      setError(err.message);
    }
  };

  return (
    <dialog id={id} className="modal">
      {/* ... existing modal structure ... */}
    </dialog>
  );
};


</div>

{/* 關於活動 */}
<div className='grid gap-y-2' style={styles.card}>
<h1 className='text-xl m-1 font-bold'>關於活動</h1>

{/* 辦理單位 */}
<div className='flex items-center'>
<svg style={styles.icon} className="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-width="2" d="M7 17v1a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1a3 3 0 0 0-3-3h-4a3 3 0 0 0-3 3Zm8-9a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
</svg>

<div className='p-2 items-center'>
<p>辦理單位</p>
<p>Lorem, ipsum dolor.</p>
</div>
</div>

{/* 學生學習護照 */}
<div className='flex items-center'>
<svg style={styles.icon} className="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-width="2" d="M11.083 5.104c.35-.8 1.485-.8 1.834 0l1.752 4.022a1 1 0 0 0 .84.597l4.463.342c.9.069 1.255 1.2.556 1.771l-3.33 2.723a1 1 0 0 0-.337 1.016l1.03 4.119c.214.858-.71 1.552-1.474 1.106l-3.913-2.281a1 1 0 0 0-1.008 0L7.583 20.8c-.764.446-1.688-.248-1.474-1.106l1.03-4.119A1 1 0 0 0 6.8 14.56l-3.33-2.723c-.698-.571-.342-1.702.557-1.771l4.462-.342a1 1 0 0 0 .84-.597l1.753-4.022Z"/>
</svg>
<div className='p-2 items-center'>
<p>學生學習護照</p>
<p>實數類型 {event.fee} 小時</p>
</div>
</div>
{/* 條件限制 */}
<div className='flex items-center'>
<svg style={styles.icon} className="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 11.917 9.724 16.5 19 7.5"/>
</svg>

<div className='p-2 items-center'>
<p>條件限制</p>
<ol className="list-decimal pl-5">
<li>開放期限:{event.start_time}.to</li>
<li>人數限制: {event.fee}</li>
<li>{event.user_id}</li>
</ol>
</div>
</div>

<p className='divider'></p>

<h1 className='text-xl font-bold'>活動說明</h1>
<p>{event.description}</p>
</div>

</div>
</div>

</div>
)
}

// In progress:

// supabase 時區顯示問題
// carousel 的顯示鈕
// 收藏的函式
// header無法正常顯示
Loading