/* eslint-disable */ /** * Cosmoe API Client * API Documentation: https://cos.world/api/v1/api_docs.html * Base URL: http://cos.moe/api/v1/ */ interface ApiResponse { code: number; msg?: string; data: T; } interface TokenResponse { user_id: number; token: string; } interface Event { id: string; // Changed from number to string based on API response name: string; description: string; event_date: string; // Changed from 'date' cover_image_url: string; // Changed from 'cover_image' description_brief: string; // Changed from 'summary' } interface TimeSlot { range: string; // e.g. "13:30-14:30" price: string; // price as string capacity: number; remaining: number; } interface EventDetail { id: number; name: string; description: string; event_date: string; // Changed from 'date' time_slots_with_prices: string; // Raw string format cover_image_url: string; // Changed from 'cover_image' detail_image_urls: string; // Changed from 'gallery' is_listed: number; login_required: number; allow_coupons: number; created_at: string; slots: TimeSlot[]; gallery: string[]; // Still exists as array of URLs } interface UserInfo { id: number; username: string; email: string; user_identity: string; role: string; is_active: number; created_at: string; } interface Statistics { total: number; completed: number; pending: number; } interface Coupon { id: number; code: string; type: string; // 'percentage' or 'fixed' value: number; valid_to: string; } interface UserProfile { user_info: UserInfo; statistics: Statistics; } interface BookingRequest { event_id: number | string; time_slot: string; user_note?: string; payment_order_id?: string; coupon_code?: string; } // Keeping ProfileData for backward compatibility interface ProfileData { user_info: UserInfo; statistics: Statistics; } interface Booking { id: number; status: string; booking_date: string; time_slot: string; final_price: string; payment_order_id: string; notes_by_user: string; created_at: string; event_name: string; } interface BookingRequest { event_id: number | string; // Changed to accept both string and number based on API response time_slot: string; user_note?: string; } export class CosmoeClient { private baseUrl = "https://cos.world/api/v1"; private userId?: number; private token?: string; /** * Get authentication token * @param username User's username * @param password User's password * @returns Token response with user_id and token */ async getToken(username: string, password: string): Promise> { const formData = new FormData(); formData.append("username", username); formData.append("password", password); const response = await fetch(`${this.baseUrl}/CreatToken.php`, { method: "POST", body: formData, }); const result: ApiResponse = await response.json(); if (result.code === 200 && result.data) { this.userId = result.data.user_id; this.token = result.data.token; } return result; } /** * Set user credentials manually * @param userId User ID * @param token Authentication token */ setCredentials(userId: number, token: string): void { this.userId = userId; this.token = token; } /** * Get current user credentials * @returns Current userId and token if authenticated */ getCredentials(): { userId: number, token: string } | null { if (this.isAuthenticated()) { return { userId: this.userId!, token: this.token! }; } return null; } /** * Check if user is authenticated */ isAuthenticated(): boolean { return !!this.userId && !!this.token; } /** * Get events list * @returns List of events */ async getEvents(): Promise> { const params = new URLSearchParams({ action: "get_events", }); const response = await fetch(`${this.baseUrl}/api.php?${params}`); return await response.json() as ApiResponse; } /** * Get event details * @param eventId Event ID to get details for * @returns Event details */ async getEventDetail(eventId: number | string): Promise> { const params = new URLSearchParams({ action: "get_event_detail", event_id: String(eventId), }); const response = await fetch(`${this.baseUrl}/api.php?${params}`); return await response.json() as ApiResponse; } /** * Get user profile and statistics * Requires authentication * @returns User profile and statistics */ async getProfile(): Promise> { if (!this.isAuthenticated()) { throw new Error("Authentication required"); } const params = new URLSearchParams({ action: "get_profile", user_id: this.userId!.toString(), token: this.token!, }); const response = await fetch(`${this.baseUrl}/api.php?${params}`); return await response.json() as ApiResponse; } /** * Get user's booking history * Requires authentication * @returns User's booking history */ async getMyBookings(): Promise> { if (!this.isAuthenticated()) { throw new Error("Authentication required"); } const params = new URLSearchParams({ action: "get_my_bookings", user_id: this.userId!.toString(), token: this.token!, }); const response = await fetch(`${this.baseUrl}/api.php?${params}`); return await response.json() as ApiResponse; } /** * Book an event * Requires authentication * @param bookingRequest Booking details * @returns Booking result */ async bookEvent(bookingRequest: BookingRequest): Promise> { if (!this.isAuthenticated()) { throw new Error("Authentication required"); } const formData = new FormData(); formData.append("action", "book_event"); formData.append("user_id", this.userId!.toString()); formData.append("token", this.token!); formData.append("event_id", String(bookingRequest.event_id)); formData.append("time_slot", bookingRequest.time_slot); formData.append("coupon_code", bookingRequest.coupon_code || ""); if (bookingRequest.user_note) { formData.append("user_note", bookingRequest.user_note); } const response = await fetch(`${this.baseUrl}/api.php`, { method: "POST", body: formData, }); return await response.json() as ApiResponse; } /** * Change user password * Requires authentication * @param currentPassword Current password * @param newPassword New password (at least 6 characters) * @returns Password change result */ async changePassword(currentPassword: string, newPassword: string): Promise> { if (!this.isAuthenticated()) { throw new Error("Authentication required"); } if (newPassword.length < 6) { throw new Error("New password must be at least 6 characters"); } const formData = new FormData(); formData.append("action", "change_password"); formData.append("user_id", this.userId!.toString()); formData.append("token", this.token!); formData.append("current_password", currentPassword); formData.append("new_password", newPassword); const response = await fetch(`${this.baseUrl}/api.php`, { method: "POST", body: formData, }); return await response.json() as ApiResponse; } /** * Get user profile with updated structure * Requires authentication * @returns User profile and statistics */ async getUserProfile(): Promise> { if (!this.isAuthenticated()) { throw new Error("Authentication required"); } const params = new URLSearchParams({ action: "get_profile", user_id: this.userId!.toString(), token: this.token!, }); const response = await fetch(`${this.baseUrl}/api.php?${params}`); return await response.json() as ApiResponse; } /** * Get available coupons for an event * Requires authentication * @param eventId Event ID to get coupons for * @returns List of available coupons */ async getAvailableCoupons(eventId: number | string): Promise> { if (!this.isAuthenticated()) { throw new Error("Authentication required"); } const params = new URLSearchParams({ action: "get_available_coupons", user_id: this.userId!.toString(), token: this.token!, event_id: String(eventId), }); const response = await fetch(`${this.baseUrl}/api.php?${params}`); return await response.json() as ApiResponse; } /** * Update booking with payment order ID * Requires authentication * @param bookingId Booking ID to update * @param paymentOrderId New payment order ID * @returns Update result */ async updatePaymentOrder(bookingId: number, paymentOrderId: string): Promise> { if (!this.isAuthenticated()) { throw new Error("Authentication required"); } const formData = new FormData(); formData.append("action", "update_payment_order"); formData.append("user_id", this.userId!.toString()); formData.append("token", this.token!); formData.append("booking_id", bookingId.toString()); formData.append("payment_order_id", paymentOrderId); const response = await fetch(`${this.baseUrl}/api.php`, { method: "POST", body: formData, }); return await response.json() as ApiResponse; } /** * Update booking note * Requires authentication * @param bookingId Booking ID to update * @param note New note * @returns Update result */ async updateBookingNote(bookingId: number, note: string): Promise> { if (!this.isAuthenticated()) { throw new Error("Authentication required"); } const formData = new FormData(); formData.append("action", "update_booking_note"); formData.append("user_id", this.userId!.toString()); formData.append("token", this.token!); formData.append("booking_id", bookingId.toString()); formData.append("note", note); const response = await fetch(`${this.baseUrl}/api.php`, { method: "POST", body: formData, }); return await response.json() as ApiResponse; } /** * Cancel a booking * Requires authentication * @param bookingId Booking ID to cancel * @returns Cancel result */ async cancelBooking(bookingId: number): Promise> { if (!this.isAuthenticated()) { throw new Error("Authentication required"); } const formData = new FormData(); formData.append("action", "cancel_booking"); formData.append("user_id", this.userId!.toString()); formData.append("token", this.token!); formData.append("booking_id", bookingId.toString()); const response = await fetch(`${this.baseUrl}/api.php`, { method: "POST", body: formData, }); return await response.json() as ApiResponse; } /** * Self reschedule a booking * Requires authentication * @param bookingId Booking ID to reschedule * @param newTimeSlot New time slot for the booking * @returns Reschedule result */ async selfReschedule(bookingId: number, newTimeSlot: string): Promise> { if (!this.isAuthenticated()) { throw new Error("Authentication required"); } const formData = new FormData(); formData.append("action", "self_reschedule"); formData.append("user_id", this.userId!.toString()); formData.append("token", this.token!); formData.append("booking_id", bookingId.toString()); formData.append("new_time_slot", newTimeSlot); const response = await fetch(`${this.baseUrl}/api.php`, { method: "POST", body: formData, }); return await response.json() as ApiResponse; } /** * Self transfer a booking to another user * Requires authentication * @param bookingId Booking ID to transfer * @param recipientUsername Username of the recipient * @returns Transfer result */ async selfTransfer(bookingId: number, recipientUsername: string): Promise> { if (!this.isAuthenticated()) { throw new Error("Authentication required"); } const formData = new FormData(); formData.append("action", "self_transfer"); formData.append("user_id", this.userId!.toString()); formData.append("token", this.token!); formData.append("booking_id", bookingId.toString()); formData.append("recipient_username", recipientUsername); const response = await fetch(`${this.baseUrl}/api.php`, { method: "POST", body: formData, }); return await response.json() as ApiResponse; } /** * Register a new user * @param key Permission key (contact admin for access) * @param username Username (2-10 characters, alphanumeric and underscore only) * @param email Email address * @param password Password (at least 6 characters) * @param userIdentity User identity (coser/photographer/other, default photographer) * @returns Registration result */ async register(key: string, username: string, email: string, password: string, userIdentity: string = "photographer"): Promise> { const formData = new FormData(); formData.append("action", "register"); formData.append("key", key); formData.append("username", username); formData.append("email", email); formData.append("password", password); formData.append("user_identity", userIdentity); const response = await fetch(`${this.baseUrl}/api.php`, { method: "POST", body: formData, }); return await response.json() as ApiResponse<{ user_id: number, username: string }>; } }