diff --git a/.env b/.env new file mode 100644 index 0000000..f06a57a --- /dev/null +++ b/.env @@ -0,0 +1,11 @@ +EXPO_PUBLIC_APPWRITE_PROJECT_ID=mobilemk +EXPO_PUBLIC_APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1 +EXPO_PUBLIC_APPWRITE_DATABASE_ID=677bd04b002bbdbe424f +EXPO_PUBLIC_APPWRITE_OGLASUVAC_COLLECTION_ID=677bd0e000393afd25b9 +EXPO_PUBLIC_APPWRITE_GALERIES_COLLECTION_ID=6787d073000bc4bdb6cb +EXPO_PUBLIC_APPWRITE_REVIEWS_COLLECTION_ID=6787d165001e6877d572 +EXPO_PUBLIC_APPWRITE_CARS_COLLECTION_ID=6787d2cb00199e6ea873 +EXPO_PUBLIC_APPWRITE_VEHICLE_COLLECTION_ID=67892473000c84b108c4 +EXPO_PUBLIC_APPWRITE_USERS_COLLECTION_ID=679289990026ad25c429 + + diff --git a/dbstructure.md b/dbstructure.md new file mode 100644 index 0000000..26e8f57 --- /dev/null +++ b/dbstructure.md @@ -0,0 +1,97 @@ +# DB + +Collections and Fields + +1. Users + + ID (default, auto-generated) + Name (string) - Full name of the user. + Email (email) - User's email address. + Phone (string) - Contact number. + ProfileImage (file) - Profile picture of the user. + Location (geo-point) - Geographical location (latitude and longitude). + CreatedAt (timestamp) - When the user registered. + +2. Cars + + ID (default, auto-generated) + Title (string) - Title or headline for the car listing. + Description (text) - Detailed description of the car. + Price (number) - Price of the car. + Make (string) - Car manufacturer (e.g., Toyota, Ford). + Model (string) - Specific model of the car. + Year (number) - Year of manufacture. + Mileage (number) - Total kilometers or miles driven. + FuelType (enum) - Type of fuel (e.g., Petrol, Diesel, Electric). + Transmission (enum) - Transmission type (e.g., Manual, Automatic). + Condition (enum) - Condition of the car (e.g., New, Used). + Images (file array) - Images of the car. + Location (geo-point) - Where the car is located. + PostedBy (relationship) - Reference to the User who posted the car. + CreatedAt (timestamp) - When the listing was created. + +3. Favorites + + ID (default, auto-generated) + UserID (relationship) - Reference to the User who favorited the car. + CarID (relationship) - Reference to the Car being favorited. + CreatedAt (timestamp) - When the favorite was added. + +4. Messages + + ID (default, auto-generated) + SenderID (relationship) - Reference to the User sending the message. + ReceiverID (relationship) - Reference to the User receiving the message. + CarID (relationship) - Reference to the Car related to the conversation. + Message (text) - Message content. + CreatedAt (timestamp) - When the message was sent. + +5. Reviews + + ID (default, auto-generated) + UserID (relationship) - Reference to the User being reviewed. + ReviewerID (relationship) - Reference to the User leaving the review. + Rating (number) - Rating score (e.g., 1–5). + Comment (text) - Review content. + CreatedAt (timestamp) - When the review was created. + +Relationships + + Users ↔ Cars: One-to-Many (A User can post multiple Cars). + Users ↔ Favorites: One-to-Many (A User can have multiple favorite Cars). + Users ↔ Messages: One-to-Many (A User can send and receive multiple Messages). + Users ↔ Reviews: One-to-Many (A User can give and receive Reviews). + +Indexes + + Cars Collection + Index on Location for geo-based searches. + Index on Price for filtering by price range. + Index on Make and Model for specific searches. + Messages Collection + Composite index on SenderID and ReceiverID for efficient message retrieval. + +CommercialSlots + + ID (default, auto-generated) + UserID (relationship) - Reference to the User who purchased the slot. + CarID (relationship) - Reference to the Car being featured. + SlotType (enum) - Type of slot (e.g., Featured, Regular). + StartDate (timestamp) - When the slot starts. + EndDate (timestamp) - When the slot ends. + Price (number) - Price paid for the slot. + PaymentStatus (enum) - Payment status (Pending, Completed, Failed). + CreatedAt (timestamp) - When the slot was purchased. + +Updated Relationships + + Users ↔ CommercialSlots: One-to-Many (A User can buy multiple commercial slots). + Cars ↔ CommercialSlots: One-to-Many (A Car can appear in multiple commercial slots of different types). + +Additional Notes + + SlotType: You can use an enum to differentiate between Featured and Regular. + Payment Tracking: If you plan to integrate payment gateways, consider adding a Transactions collection to track payments comprehensively. + Slot Duration Logic: Ensure validations in your backend (or Appwrite Functions) to enforce slot duration limits and prevent overlapping slots for the same car. + +Would you like me to expand on payment tracking or slot scheduling logic? diff --git a/lib/appwrite.ts b/lib/appwrite.ts index 452f137..0d8b57d 100644 --- a/lib/appwrite.ts +++ b/lib/appwrite.ts @@ -4,15 +4,26 @@ import {openAuthSessionAsync} from "expo-web-browser"; import {attribute} from "postcss-selector-parser"; import limit from "ajv-formats/src/limit"; +// Add this debug log +// console.log('Environment Variables:', { +// endpoint: process.env.EXPO_PUBLIC_APPWRITE_ENDPOINT, +// projectId: process.env.EXPO_PUBLIC_APPWRITE_PROJECT_ID, +// }); + +if (!process.env.EXPO_PUBLIC_APPWRITE_ENDPOINT || !process.env.EXPO_PUBLIC_APPWRITE_PROJECT_ID) { + throw new Error('Missing required Appwrite environment variables'); +} + export const config = { platform: 'com.placebomk.mobilemk', endpoint: process.env.EXPO_PUBLIC_APPWRITE_ENDPOINT, projectId: process.env.EXPO_PUBLIC_APPWRITE_PROJECT_ID, databaseId: process.env.EXPO_PUBLIC_APPWRITE_DATABASE_ID, - oglasuvacId: process.env.EXPO_PUBLIC_APPWRITE_OGLASUVAC_COLLECTION_ID, - galleryId: process.env.EXPO_PUBLIC_APPWRITE_GALERIES_COLLECTION_ID, - reviewId: process.env.EXPO_PUBLIC_APPWRITE_REVIEWS_COLLECTION_ID, - vehicleId: process.env.EXPO_PUBLIC_APPWRITE_VEHICLE_COLLECTION_ID, + usersId: process.env.EXPO_PUBLIC_APPWRITE_USERS_COLLECTION_ID, + // oglasuvacId: process.env.EXPO_PUBLIC_APPWRITE_OGLASUVAC_COLLECTION_ID, + // galleryId: process.env.EXPO_PUBLIC_APPWRITE_GALERIES_COLLECTION_ID, + // reviewId: process.env.EXPO_PUBLIC_APPWRITE_REVIEWS_COLLECTION_ID, + // vehicleId: process.env.EXPO_PUBLIC_APPWRITE_VEHICLE_COLLECTION_ID, } export const client = new Client(); @@ -80,35 +91,73 @@ export async function getCurrentUser() { export async function logOut(): Promise { try { - const result = await account.deleteSession('current'); - return result + await account.deleteSession('current'); + return true; } catch (error) { console.error("Failed to log out user:", error); return false; } } -export async function getData() { - try { - const result =await databases.listDocuments( - config.databaseId!, - config.vehicleId!, - [Query.orderAsc(`$createdAt`), Query.limit(5)], +// export async function getData() { +// try { +// const result =await databases.listDocuments( +// config.databaseId!, +// config.vehicleId!, +// [Query.orderAsc(`$createdAt`), Query.limit(5)], - ) - console.log(result.documents) - return result.documents; - } - catch (error) { - console.error("Failed to fetch data:", error); - return []; +// ) +// console.log(result.documents) +// return result.documents; +// } +// catch (error) { +// console.error("Failed to fetch data:", error); +// return []; +// } +// } + +// export async function getVehicles({filter, query, limit}: { +// filter?: string; +// query?: string; +// limit?: number; +// }){ + +// } + +export async function saveUserToDatabase(userData: { + userId: string; + name: string; + email: string; + avatar: string; +}) { + try { + // First check if user already exists + try { + await databases.getDocument( + config.databaseId!, + config.usersId!, + userData.userId + ); + console.log('User already exists in database'); + return null; + } catch (error) { + // User doesn't exist, proceed with creation + const result = await databases.createDocument( + config.databaseId!, + config.usersId!, + userData.userId, + { + name: userData.name, + email: userData.email, + avatar: userData.avatar, + createdAt: new Date().toISOString(), + } + ); + console.log('User created successfully'); + return result; + } + } catch (error) { + console.error("Failed to save user data:", error); + return null; } } - -export async function getVehicles({filter, query, limit}: { - filter?: string; - query?: string; - limit?: number; -}){ - -} \ No newline at end of file diff --git a/lib/globalProvider.tsx b/lib/globalProvider.tsx index 5633d60..2605b7d 100644 --- a/lib/globalProvider.tsx +++ b/lib/globalProvider.tsx @@ -1,9 +1,10 @@ -import React, { createContext, useContext, ReactNode } from "react"; - +import React, { createContext, useContext, ReactNode, useEffect } from "react"; +import { saveUserToDatabase } from "./appwrite"; import { getCurrentUser } from "./appwrite"; import { useAppwrite } from "./useAppwrite"; import { Redirect } from "expo-router"; // import {replace} from "@remix-run/router"; +import { config } from "./appwrite"; interface GlobalContextType { isLoggedIn: boolean; @@ -34,6 +35,18 @@ export const GlobalProvider = ({ children }: {children: ReactNode}) => { fn: getCurrentUser, }); + useEffect(() => { + if (user && !loading) { + // Save user data when they first log in + saveUserToDatabase({ + userId: user.$id, + name: user.name, + email: user.email, + avatar: user.avatar, + }); + } + }, [user, loading]); + const isLoggedIn = !!user; console.log(JSON.stringify(user));