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

feat : shows events info from supabase on event index page #123

Merged
merged 8 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .env.example

This file was deleted.

12 changes: 12 additions & 0 deletions src/components/icons/ClockIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

import React from 'react';
import IconProps from '../interface/IconProps';
import { BasicIcon } from './BasicIcon';

export const ClockIcon: React.FC<IconProps> = ({ fill, stroke, size }) => (
<BasicIcon fill={fill} stroke={stroke} size={size}>
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M12 8v4l3 3m6-3a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/>
</BasicIcon>
);
1989ONCE marked this conversation as resolved.
Show resolved Hide resolved

export default ClockIcon;
12 changes: 12 additions & 0 deletions src/components/icons/PinIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

import React from 'react';
import IconProps from '../interface/IconProps';
import { BasicIcon } from './BasicIcon';

export const PinIcon: React.FC<IconProps> = ({ fill, stroke, size }) => (
<BasicIcon fill={fill} stroke={stroke} size={size}>
<path fill-rule="evenodd" d="m7.539 14.841.003.003.002.002a.755.755 0 0 0 .912 0l.002-.002.003-.003.012-.009a5.57 5.57 0 0 0 .19-.153 15.588 15.588 0 0 0 2.046-2.082c1.101-1.362 2.291-3.342 2.291-5.597A5 5 0 0 0 3 7c0 2.255 1.19 4.235 2.292 5.597a15.591 15.591 0 0 0 2.046 2.082 8.916 8.916 0 0 0 .189.153l.012.01ZM8 8.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z" clip-rule="evenodd" />
</BasicIcon>
);

export default PinIcon;
2 changes: 2 additions & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ export { Header } from './Header';
// Icons
export { BellIcon } from './icons/BellIcon';
export { CalendarIcon } from './icons/CalendarIcon';
export { ClockIcon } from './icons/ClockIcon';
export { LogoutIcon } from './icons/LogoutIcon';
export { PinIcon } from './icons/PinIcon';
export { PlusIcon } from './icons/PlusIcon';
export { SidebarArrowDownIcon } from './icons/SidebarArrowDownIcon';
export { SidebarArrowRightIcon } from './icons/SidebarArrowRightIcon';
Expand Down
15 changes: 15 additions & 0 deletions src/routes/events/create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ function CreateEventScreen() {
const [preview, setPreview] = useState<string>()
const [inputs, setInputs] = useState({
name: '',
start_time: '',
end_time: '',
location: '',
fee: 0,
description: ''
})

// create a preview as a side effect, whenever selected file is changed
Expand Down Expand Up @@ -106,6 +111,8 @@ function CreateEventScreen() {
type="datetime-local"
id="start-time"
name="start-time"
value={inputs.start_time}
onChange={(text) => { setInputs({ ...inputs, start_time: text.target.value }) }}
/>
</div>
<div className="flex gap-3 mt-3 ms-4">
Expand All @@ -114,25 +121,33 @@ function CreateEventScreen() {
type="datetime-local"
id="end-time"
name="end-time"
value={inputs.end_time}
onChange={(text) => { setInputs({ ...inputs, end_time: text.target.value }) }}
/>
</div>
<p style={styles.text}>活動地點</p>
<input
style={styles.input}
className="rounded"
placeholder="請輸入活動地點"
value={inputs.location}
onChange={(text) => { setInputs({ ...inputs, location: text.target.value }) }}
/>
<p style={styles.text}>參加費用</p>
<input
style={styles.input}
className="rounded"
placeholder="請輸入參加費用(請輸入數字,無則填0)"
value={inputs.fee}
onChange={(text) => { setInputs({ ...inputs, fee: Number(text.target.value) }) }}
1989ONCE marked this conversation as resolved.
Show resolved Hide resolved
/>
<p style={styles.text}>活動介紹</p>
<input
style={styles.input}
className="rounded"
placeholder="請介紹你的活動"
value={inputs.description}
onChange={(text) => { setInputs({ ...inputs, description: text.target.value }) }}
/>
</div>
<div className='mt-3 ms-2'>
Expand Down
96 changes: 75 additions & 21 deletions src/routes/events/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { createFileRoute, Link } from '@tanstack/react-router';
import { BellIcon, Header, PlusIcon } from '../../components';
import { createFileRoute } from '@tanstack/react-router';
import { Clock } from "flowbite-react-icons/solid";
import { BellIcon, Header, PinIcon, PlusIcon } from '../../components';
import { AuthGuard } from '../../utils/auth';
import { supabase } from '../../utils/supabase';
interface Event {
created_at: string;
description: string | null;
end_time: string | null;
fee: number | null;
id: number;
name: string | null;
start_time: string | null;
type: number | null;
user_id: string;
location: string | null;
}

const styles = {
container: {
flex: 1,
backgroundColor: '#333333',
},
};
export const Route = createFileRoute('/events/')({
beforeLoad: AuthGuard,
loader: async () => {
Expand All @@ -19,7 +26,6 @@ export const Route = createFileRoute('/events/')({
if (error !== null) {
throw error
}

return { events: data }
},
component: EventIndex
Expand All @@ -28,23 +34,41 @@ export const Route = createFileRoute('/events/')({
function EventIndex() {
const { events } = Route.useLoaderData()
const navigate = Route.useNavigate();

// console.log(events[0].start_time)

return (
<>
<div className="container mx-auto">
<Header />
<div style={styles.container}>
<h1 style={{ marginLeft: 140 }} className='text-lg text-white'>活動列表</h1>
{
events.map((event) => (
<Link key={event.id} to='/events/$eventId' params={{ eventId: event.id.toString() }} >{event.name}</Link>
))
}
<div className="flex-1 bg-gray-800 p-4">
<h1 className="ml-4 text-xl text-white">最新揪人</h1>
<div className="overflow-x-auto mt-2">
<div className="flex space-x-4">
{events.map((event) => (
<EventCard key={event.id} event={event} />
))}
</div>
</div>

<h1 className="ml-4 text-xl text-white mt-8">最新活動</h1>
<div className="overflow-x-auto mt-2">
<div className="flex space-x-4">
{events.map((event) => (
<EventCard key={event.id} event={event} />
))}
</div>
</div>
</div>
<button className="btn btn-circle fixed right-4 bottom-4" onClick={()=>{
if(document){
(document.getElementById('my_modal_4') as HTMLFormElement).showModal();

<button
className="btn btn-circle fixed right-4 bottom-4"
onClick={() => {
if (document) {
(document.getElementById('my_modal_4') as HTMLFormElement).showModal();
}
}}>
}}
>
1989ONCE marked this conversation as resolved.
Show resolved Hide resolved
<PlusIcon />
<dialog id="my_modal_4" className="modal">
<div className="modal-box w-11/12 max-w-5xl">
Expand All @@ -54,7 +78,12 @@ function EventIndex() {
</div>
<p className="py-4 text-xl">確定要新增嗎?</p>
<div className="modal-action flex justify-between">
<button className="btn w-1/2" onClick={() => navigate({ to: '/events/create' })}>好</button>
<button
className="btn w-1/2"
onClick={() => navigate({ to: '/events/create' })}
>
</button>
<form method="dialog" className="w-1/2">
{/* This button will close the dialog */}
<button className="btn w-full">取消</button>
Expand All @@ -67,3 +96,28 @@ function EventIndex() {
</>
)
}

function EventCard({ event }: { event: Event }) {
const startTime = event.start_time ? new Date(event.start_time) : new Date();
return (
1989ONCE marked this conversation as resolved.
Show resolved Hide resolved
<div className="flex-shrink-0 w-40 bg-gray-700 rounded-lg overflow-hidden text-white">
<div className="h-32 bg-gray-500" />
<div className="p-2">
<h3 className="text-lg mb-1">{event.name}</h3>
<p className="text-sm flex items-center">
<Clock fill="currentColor" stroke="#ffffff" size={24} />
{startTime.toLocaleString('zh-TW', {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
})}
</p>
<p className="text-sm flex items-center">
1989ONCE marked this conversation as resolved.
Show resolved Hide resolved
<PinIcon fill="currentColor" stroke="#ffffff" size={24} />
{event.location || '位置未提供'}
</p>
</div>
</div>
);
}
3 changes: 3 additions & 0 deletions src/utils/database.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export type Database = {
end_time: string | null
fee: number | null
id: number
location: string | null
name: string | null
start_time: string | null
type: number | null
Expand All @@ -67,6 +68,7 @@ export type Database = {
end_time?: string | null
fee?: number | null
id?: number
location?: string | null
name?: string | null
start_time?: string | null
type?: number | null
Expand All @@ -78,6 +80,7 @@ export type Database = {
end_time?: string | null
fee?: number | null
id?: number
location?: string | null
name?: string | null
start_time?: string | null
type?: number | null
Expand Down
3 changes: 3 additions & 0 deletions supabase/migrations/20241114141253_remote_schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
alter table "public"."events" add column "location" text;


Loading