Skip to content

Commit 2920769

Browse files
authored
Merge pull request NCUAppTeam#138 from 1989ONCE/login-test
test commit
2 parents 877acee + 854a9d2 commit 2920769

File tree

12 files changed

+425
-8
lines changed

12 files changed

+425
-8
lines changed

package-lock.json

Lines changed: 15 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"flowbite-react-icons": "^1.1.0",
1818
"react": "^18.3.1",
1919
"react-dom": "^18.3.1",
20-
"supabase": "^1.223.10"
20+
"spin-wheel-game": "^1.0.3-alpha.3",
21+
"supabase": "^1.226.4"
2122
},
2223
"devDependencies": {
2324
"@playwright/test": "^1.47.0",
@@ -46,4 +47,4 @@
4647
"sharp": "0.32.6",
4748
"sharp-ico": "0.1.5"
4849
}
49-
}
50+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import ErrorHandler from "../../../utils/ErrorHandler";
2+
import { supabase } from "../../../utils/supabase";
3+
4+
import Event, { DBEvent } from '../Entities/Restaurant';
5+
import EventService from "../Services/RestaurantService";
6+
7+
8+
const EVENT_TABLE_NAME = "restaurant"
9+
10+
11+
/**
12+
* Controller for handling restaurant-related operations.
13+
*
14+
* This class provides methods to interact with the restaurant database.
15+
*
16+
* @remarks
17+
* The original database service was authored by @yeahlowflicker. This implementation
18+
* has been modified and extended by @1989ONCE.
19+
*
20+
* @author Susan C.(@1989ONCE)
21+
*/
22+
export default class RestaurantController {
23+
24+
25+
/**
26+
* Get an array of events
27+
*
28+
* @usage eventController.getEvents(<PARAMS>).then(
29+
* (events: Array<Events>) => { ... }
30+
* )
31+
*
32+
* @param {string} fields - The columns to retrieve (comma-separated)
33+
* @param {string} orderBy - Which field to order by (leave blank if not needed)
34+
* @param {boolean} orderDescending - Whether to order in descending order (defaults to false)
35+
* @param {number} rangeStart - Starting index of fetch (defaults to 0)
36+
* @param {number} rangeEnd - Ending index of fetch (defaults to 100)
37+
*
38+
* @returns {Array<Event>} - Array of events
39+
*
40+
* @see [https://supabase.com/docs/reference/javascript/order]
41+
* @see [https://supabase.com/docs/reference/javascript/range]
42+
*
43+
* @template author Henry C. (@yeahlowflicker)
44+
* @
45+
*/
46+
public async getAllRestaurant(
47+
fields: string,
48+
orderBy?: string,
49+
orderDescending?: boolean,
50+
rangeStart?: number,
51+
rangeEnd?: number
52+
) : Promise<Array<Event> | null> {
53+
54+
const query = supabase
55+
.from(EVENT_TABLE_NAME)
56+
.select(fields)
57+
.returns<Array<DBEvent>>()
58+
59+
if (orderBy)
60+
query.order(orderBy, { ascending: !orderDescending })
61+
62+
if (rangeStart !== undefined && rangeEnd !== undefined)
63+
query.range(rangeStart, rangeEnd)
64+
65+
const { data, error } = await query
66+
67+
// Error handling
68+
if (error) {
69+
ErrorHandler.handleSupabaseError(error)
70+
return null
71+
}
72+
73+
// Initialize result array
74+
const events : Array<Event> = []
75+
76+
77+
// For each found DBEvent, convert to Event and append to result array
78+
data.forEach((record: DBEvent) => {
79+
events.push(
80+
EventService.parseEvent(record)
81+
)
82+
})
83+
84+
return events
85+
}
86+
87+
88+
89+
/**
90+
* Find a single event by ID
91+
*
92+
* @usage eventController.FindEventByID(<PARAMS>).then(
93+
* (event: Event) => { ... }
94+
* )
95+
*
96+
* @param {string} eventID - Target event ID
97+
* @param {string} fields - The columns to retrieve
98+
*
99+
* @returns {Event} - The target event entity (null if not found)
100+
*
101+
* @author Henry C. (@yeahlowflicker)
102+
*/
103+
public async findEventByID(eventID: string, fields?: string) : Promise<Event | null> {
104+
105+
const { data, error } = await supabase
106+
.from(EVENT_TABLE_NAME)
107+
.select(fields)
108+
.eq("id", eventID)
109+
.returns<DBEvent>()
110+
.limit(1)
111+
.single()
112+
113+
// Error handling
114+
if (error) {
115+
ErrorHandler.handleSupabaseError(error)
116+
return null
117+
}
118+
119+
if (!data)
120+
return null
121+
122+
// Type conversion: DBEvent -> Event
123+
const event : Event = EventService.parseEvent(data)
124+
125+
return event
126+
}
127+
128+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Database } from "../../../utils/database.types";
2+
3+
/**
4+
* This is a dummy-type inherited from the generated Supabase type
5+
*/
6+
export type DBEvent = Database['public']['Tables']['events']['Row'];
7+
8+
9+
export default class Event {
10+
11+
public id: number = 0;
12+
public name: string = "";
13+
public type: number = 0;
14+
public description: string = "";
15+
public startTime: string = "";
16+
public endTime: string = "";
17+
public location: string = "";
18+
public fee: number = 0;
19+
public userID: string = "";
20+
public createdAt: string = "";
21+
22+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import Event, { DBEvent } from "../Entities/Restaurant";
2+
3+
const EventService = {
4+
5+
parseEvent(record: DBEvent) : Event {
6+
if (!record || typeof record !== 'object')
7+
throw new Error('Invalid record provided')
8+
9+
if (!record.id)
10+
throw new Error('id is a required field')
11+
12+
const event = new Event()
13+
14+
event.id = record.id
15+
event.name = record.name ?? ""
16+
event.type = typeof record.type === 'number' ? record.type : 0
17+
event.description = record.description ?? ""
18+
event.startTime = record.start_time ? new Date(record.start_time).toISOString() : ""
19+
event.endTime = record.end_time ? new Date(record.end_time).toISOString() : ""
20+
event.location = record.location ?? ""
21+
event.fee = typeof record.fee === 'number' ? record.fee : 0
22+
event.userID = record.user_id
23+
event.createdAt = record.created_at ? new Date(record.created_at).toISOString() : ""
24+
25+
return event
26+
}
27+
28+
}
29+
30+
export default EventService
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
export function DinnerCard({ restaurant }: { restaurant: Event }) {
3+
4+
return (
5+
<div className="flex-shrink-0 w-40 rounded-lg overflow-hidden text-white">
6+
<div className="h-32 bg-gray-500" />
7+
<div className="p-2 bg-white">
8+
<h3 className="text-lg mb-1 text-black">{ }</h3>
9+
10+
</div>
11+
</div>
12+
);
13+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { ISpinWheelProps, SpinWheel } from 'spin-wheel-game';
2+
export const MySpinWheel = () => {
3+
4+
const segments = [
5+
{ segmentText: 'Option 1', segColor: 'red' },
6+
{ segmentText: 'Option 2', segColor: 'blue' },
7+
{ segmentText: 'Option 3', segColor: 'green' },
8+
// Add more segments as needed
9+
];
10+
11+
const handleSpinFinish = (result: string) => {
12+
console.log(`Spun to: ${result}`);
13+
// Handle the result as needed
14+
};
15+
16+
const spinWheelProps: ISpinWheelProps = {
17+
segments,
18+
onFinished: handleSpinFinish,
19+
primaryColor: 'black',
20+
contrastColor: 'white',
21+
buttonText: 'Spin',
22+
isOnlyOnce: false,
23+
size: 290,
24+
upDuration: 100,
25+
downDuration: 600,
26+
fontFamily: 'Arial',
27+
arrowLocation: 'top',
28+
showTextOnSpin: true,
29+
isSpinSound: true,
30+
};
31+
32+
return (
33+
<div className='mx-auto mt-4'>
34+
<h4>請選擇5-10家餐廳作為輪盤選項</h4>
35+
36+
<SpinWheel {...spinWheelProps} />
37+
</div >
38+
);
39+
40+
};

0 commit comments

Comments
 (0)