diff --git a/NEXT_STEPS.md b/NEXT_STEPS.md deleted file mode 100644 index ad6fc21..0000000 --- a/NEXT_STEPS.md +++ /dev/null @@ -1,137 +0,0 @@ -# Rentify - Next Steps - -## Hiện trạng - -Đã xây dựng cấu trúc cơ bản cho dự án Rentify với: - -- Cấu trúc dự án Next.js với App Router -- Các components UI chính: Navbar, Footer, SearchBar, PropertyCard, FeaturedListings, HowItWorks, TestimonialsSection -- Schema Prisma cho cơ sở dữ liệu -- Cấu hình NextAuth.js cho xác thực người dùng -- API route cơ bản cho việc tìm kiếm phòng trọ - -## Các bước tiếp theo - -### 1. Cài đặt và cấu hình - -- Cài đặt các dependencies cần thiết: - ```bash - npm install - ``` -- Tạo file `.env` từ `.env.example` và cập nhật các biến môi trường -- Khởi tạo cơ sở dữ liệu: - ```bash - npx prisma db push - ``` - -### 2. Hoàn thiện UI/UX - -- **Trang đăng ký và đăng nhập**: - - - Tạo form đăng ký và đăng nhập người dùng - - Tích hợp với NextAuth.js - -- **Trang hồ sơ người dùng**: - - - Chỉnh sửa thông tin cá nhân - - Đổi mật khẩu - - Upload avatar - -- **Trang danh sách phòng trọ**: - - - Hiển thị kết quả tìm kiếm - - Pagination - - Lọc nâng cao - -- **Trang chi tiết phòng trọ**: - - - Trình chiếu hình ảnh - - Thông tin chi tiết - - Bản đồ vị trí - - Phần liên hệ chủ trọ - -- **Trang đăng tin**: - - Form đăng tin với upload nhiều hình ảnh - - Chọn vị trí trên bản đồ - - Xem trước tin đăng - -### 3. Phát triển API và chức năng - -- **Quản lý người dùng**: - - - Đăng ký, đăng nhập, đăng xuất - - Quản lý profile - - Phân quyền (User, Host, Admin) - -- **Quản lý tin đăng**: - - - CRUD cho tin đăng - - Upload và quản lý hình ảnh với Cloudinary - - Kiểm duyệt tin đăng - -- **Tính năng yêu thích**: - - - Thêm/xóa tin đăng khỏi danh sách yêu thích - - Xem danh sách yêu thích - -- **Hệ thống tin nhắn**: - - - Chat real-time giữa người dùng - - Thông báo tin nhắn mới - -- **Đặt lịch xem phòng**: - - - Tạo lịch hẹn - - Xác nhận/từ chối lịch hẹn - - Nhắc nhở lịch hẹn - -- **Tích hợp bản đồ**: - - Hiển thị vị trí phòng trọ trên bản đồ - - Tìm kiếm theo bản đồ - -### 4. Tối ưu hóa - -- **SEO**: - - - Metadata cho từng trang - - Sitemap - - robots.txt - -- **Performance**: - - - Lazy loading cho hình ảnh - - Code splitting - - Caching - -- **Testing**: - - - Unit tests - - Integration tests - - E2E tests - -- **Deployment**: - - CI/CD - - Môi trường staging và production - -## Hướng dẫn cho người phát triển - -### Quy trình làm việc - -1. Làm việc trên nhánh riêng cho mỗi tính năng/fix -2. Tạo PR để review code trước khi merge vào main -3. Viết test cho các tính năng mới - -### Coding guidelines - -- Sử dụng TypeScript cho type-safe -- Tuân thủ linters (ESLint) và formatters (Prettier) -- Sử dụng các design patterns phù hợp - -### Tài liệu tham khảo - -- [Next.js Documentation](https://nextjs.org/docs) -- [Prisma Documentation](https://www.prisma.io/docs) -- [NextAuth.js Documentation](https://next-auth.js.org/getting-started/introduction) -- [Tailwind CSS Documentation](https://tailwindcss.com/docs) -- [React Hook Form Documentation](https://react-hook-form.com/get-started) -- [TanStack Query Documentation](https://tanstack.com/query/latest/docs/react/overview) diff --git a/README-INTEGRATION.md b/README-INTEGRATION.md deleted file mode 100644 index f09f737..0000000 --- a/README-INTEGRATION.md +++ /dev/null @@ -1,116 +0,0 @@ -# Hướng dẫn tích hợp Next.js và Spring Boot - -Dự án này tích hợp Next.js (frontend) và Spring Boot (backend) để tạo ứng dụng web đầy đủ tính năng. - -## Cấu trúc dự án - -- **Next.js (Frontend)**: Chạy trên port 3000 -- **Spring Boot (Backend)**: Chạy trên port 8080 - -## Cài đặt và chạy dự án - -### Bước 1: Chạy Spring Boot server - -1. Mở terminal và chạy Maven: - -```bash -mvn clean install -mvn spring-boot:run -``` - -Hoặc mở dự án trong Eclipse/IntelliJ và chạy `SpringBootWebApplication.java`. - -2. Kiểm tra Spring Boot API đang hoạt động bằng cách truy cập: - - http://localhost:8080/api/hello - -### Bước 2: Chạy Next.js frontend - -1. Mở terminal khác và cài đặt các dependencies (nếu chưa có): - -```bash -npm install -``` - -2. Chạy server phát triển: - -```bash -npm run dev -``` - -3. Mở trình duyệt và truy cập: - - http://localhost:3000 - - http://localhost:3000/api-test (để kiểm tra kết nối) - -## Cách gọi API từ Next.js - -1. Sử dụng thư viện Axios đã được cấu hình trong `lib/api.ts`: - -```typescript -import api from "@/lib/api"; - -// Gọi API -const response = await api.get("/endpoint"); -const data = response.data; -``` - -2. Tạo thêm các hàm API mới trong `lib/api.ts`: - -```typescript -export const fetchData = async () => { - try { - const response = await api.get("/your-endpoint"); - return response.data; - } catch (error) { - console.error("Error fetching data:", error); - throw error; - } -}; -``` - -## Tạo API Spring Boot mới - -1. Tạo các endpoint mới trong `src/main/java/com/javaweb/api/web/ApiController.java`: - -```java -@GetMapping("/data") -public ResponseEntity getData() { - // Xử lý logic - return ResponseEntity.ok(yourData); -} - -@PostMapping("/create") -public ResponseEntity createData(@RequestBody YourRequestType request) { - // Xử lý logic - return ResponseEntity.ok(createdData); -} -``` - -## Xử lý lỗi phổ biến - -1. **CORS Error**: Đã cấu hình CORS trong `WebConfig.java`. Nếu vẫn gặp lỗi, hãy kiểm tra: - - - Origin URL đúng (http://localhost:3000) - - Headers và Methods được cho phép - -2. **Connection Refused**: Kiểm tra: - - - Spring Boot server đang chạy - - Port 8080 không bị chặn hoặc sử dụng bởi ứng dụng khác - -3. **404 Not Found**: Kiểm tra: - - Đường dẫn API chính xác - - RequestMapping và Endpoint đúng - -## Triển khai (Deployment) - -Khi triển khai lên môi trường production: - -1. Cập nhật URL API trong `lib/api.ts` để trỏ đến URL server thực -2. Cập nhật CORS trong `WebConfig.java` để cho phép domain production -3. Cấu hình các biến môi trường trong file `.env` của Next.js - -## Mở rộng - -1. Thêm xác thực JWT -2. Cài đặt Redux hoặc Context API để quản lý state -3. Tích hợp WebSocket cho real-time updates diff --git a/prisma/migrations/20250418081719_initial/migration.sql b/prisma/migrations/20250418081719_initial/migration.sql deleted file mode 100644 index 3af113f..0000000 --- a/prisma/migrations/20250418081719_initial/migration.sql +++ /dev/null @@ -1,250 +0,0 @@ --- CreateEnum -CREATE TYPE "Role" AS ENUM ('USER', 'HOST', 'ADMIN'); - --- CreateEnum -CREATE TYPE "PropertyType" AS ENUM ('ROOM', 'APARTMENT', 'HOUSE', 'STUDIO', 'SHARED'); - --- CreateEnum -CREATE TYPE "PropertyStatus" AS ENUM ('AVAILABLE', 'RENTED', 'HIDDEN'); - --- CreateEnum -CREATE TYPE "AppointmentStatus" AS ENUM ('PENDING', 'CONFIRMED', 'CANCELLED', 'COMPLETED'); - --- CreateTable -CREATE TABLE "User" ( - "id" TEXT NOT NULL, - "name" TEXT, - "email" TEXT NOT NULL, - "emailVerified" TIMESTAMP(3), - "hashedPassword" TEXT, - "image" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "role" "Role" NOT NULL DEFAULT 'USER', - - CONSTRAINT "User_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Account" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "type" TEXT NOT NULL, - "provider" TEXT NOT NULL, - "providerAccountId" TEXT NOT NULL, - "refresh_token" TEXT, - "access_token" TEXT, - "expires_at" INTEGER, - "token_type" TEXT, - "scope" TEXT, - "id_token" TEXT, - "session_state" TEXT, - - CONSTRAINT "Account_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Session" ( - "id" TEXT NOT NULL, - "sessionToken" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "expires" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "Session_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "VerificationToken" ( - "identifier" TEXT NOT NULL, - "token" TEXT NOT NULL, - "expires" TIMESTAMP(3) NOT NULL -); - --- CreateTable -CREATE TABLE "Property" ( - "id" TEXT NOT NULL, - "title" TEXT NOT NULL, - "description" TEXT NOT NULL, - "price" INTEGER NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "userId" TEXT NOT NULL, - "address" TEXT NOT NULL, - "city" TEXT NOT NULL, - "district" TEXT NOT NULL, - "ward" TEXT, - "latitude" DOUBLE PRECISION, - "longitude" DOUBLE PRECISION, - "area" DOUBLE PRECISION NOT NULL, - "bedrooms" INTEGER, - "bathrooms" INTEGER, - "propertyType" "PropertyType" NOT NULL, - "status" "PropertyStatus" NOT NULL DEFAULT 'AVAILABLE', - "isFeatured" BOOLEAN NOT NULL DEFAULT false, - "views" INTEGER NOT NULL DEFAULT 0, - - CONSTRAINT "Property_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Image" ( - "id" TEXT NOT NULL, - "url" TEXT NOT NULL, - "publicId" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "propertyId" TEXT, - "listingId" TEXT, - - CONSTRAINT "Image_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Amenity" ( - "id" TEXT NOT NULL, - "name" TEXT NOT NULL, - "icon" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "Amenity_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "PropertyAmenity" ( - "propertyId" TEXT NOT NULL, - "amenityId" TEXT NOT NULL, - - CONSTRAINT "PropertyAmenity_pkey" PRIMARY KEY ("propertyId","amenityId") -); - --- CreateTable -CREATE TABLE "Favorite" ( - "userId" TEXT NOT NULL, - "propertyId" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "Favorite_pkey" PRIMARY KEY ("userId","propertyId") -); - --- CreateTable -CREATE TABLE "Message" ( - "id" TEXT NOT NULL, - "content" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "senderId" TEXT NOT NULL, - "receiverId" TEXT NOT NULL, - "isRead" BOOLEAN NOT NULL DEFAULT false, - - CONSTRAINT "Message_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Appointment" ( - "id" TEXT NOT NULL, - "date" TIMESTAMP(3) NOT NULL, - "status" "AppointmentStatus" NOT NULL DEFAULT 'PENDING', - "notes" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "userId" TEXT NOT NULL, - "hostId" TEXT NOT NULL, - "propertyId" TEXT NOT NULL, - - CONSTRAINT "Appointment_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Listing" ( - "id" TEXT NOT NULL, - "title" TEXT NOT NULL, - "description" TEXT NOT NULL, - "price" DOUBLE PRECISION NOT NULL, - "area" DOUBLE PRECISION NOT NULL, - "bedrooms" INTEGER, - "bathrooms" INTEGER, - "amenities" TEXT[], - "type" TEXT NOT NULL, - "locationId" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "Listing_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Location" ( - "id" TEXT NOT NULL, - "latitude" DOUBLE PRECISION NOT NULL, - "longitude" DOUBLE PRECISION NOT NULL, - "address" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "Location_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); - --- CreateIndex -CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId"); - --- CreateIndex -CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken"); - --- CreateIndex -CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token"); - --- CreateIndex -CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token"); - --- CreateIndex -CREATE UNIQUE INDEX "Amenity_name_key" ON "Amenity"("name"); - --- CreateIndex -CREATE UNIQUE INDEX "Listing_locationId_key" ON "Listing"("locationId"); - --- AddForeignKey -ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Property" ADD CONSTRAINT "Property_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Image" ADD CONSTRAINT "Image_propertyId_fkey" FOREIGN KEY ("propertyId") REFERENCES "Property"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Image" ADD CONSTRAINT "Image_listingId_fkey" FOREIGN KEY ("listingId") REFERENCES "Listing"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "PropertyAmenity" ADD CONSTRAINT "PropertyAmenity_propertyId_fkey" FOREIGN KEY ("propertyId") REFERENCES "Property"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "PropertyAmenity" ADD CONSTRAINT "PropertyAmenity_amenityId_fkey" FOREIGN KEY ("amenityId") REFERENCES "Amenity"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Favorite" ADD CONSTRAINT "Favorite_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Favorite" ADD CONSTRAINT "Favorite_propertyId_fkey" FOREIGN KEY ("propertyId") REFERENCES "Property"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Message" ADD CONSTRAINT "Message_senderId_fkey" FOREIGN KEY ("senderId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Message" ADD CONSTRAINT "Message_receiverId_fkey" FOREIGN KEY ("receiverId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_hostId_fkey" FOREIGN KEY ("hostId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_propertyId_fkey" FOREIGN KEY ("propertyId") REFERENCES "Property"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Listing" ADD CONSTRAINT "Listing_locationId_fkey" FOREIGN KEY ("locationId") REFERENCES "Location"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml deleted file mode 100644 index fbffa92..0000000 --- a/prisma/migrations/migration_lock.toml +++ /dev/null @@ -1,3 +0,0 @@ -# Please do not edit this file manually -# It should be added in your version-control system (i.e. Git) -provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma deleted file mode 100644 index 01b9d80..0000000 --- a/prisma/schema.prisma +++ /dev/null @@ -1,191 +0,0 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "postgresql" - url = env("DATABASE_URL") -} - -model User { - id String @id @default(cuid()) - name String? - email String @unique - emailVerified DateTime? - hashedPassword String? - image String? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - role Role @default(USER) - - accounts Account[] - sessions Session[] - properties Property[] - favorites Favorite[] - messages Message[] @relation("UserMessages") - receivedMessages Message[] @relation("ReceivedMessages") - appointments Appointment[] @relation("UserAppointments") - hostAppointments Appointment[] @relation("HostAppointments") -} - -model Account { - id String @id @default(cuid()) - userId String - type String - provider String - providerAccountId String - refresh_token String? @db.Text - access_token String? @db.Text - expires_at Int? - token_type String? - scope String? - id_token String? @db.Text - session_state String? - - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - - @@unique([provider, providerAccountId]) -} - -model Session { - id String @id @default(cuid()) - sessionToken String @unique - userId String - expires DateTime - user User @relation(fields: [userId], references: [id], onDelete: Cascade) -} - -model VerificationToken { - identifier String - token String @unique - expires DateTime - - @@unique([identifier, token]) -} - -model Property { - id String @id @default(cuid()) - title String - description String @db.Text - price Int - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - userId String - address String - city String - district String - ward String? - latitude Float? - longitude Float? - area Float - bedrooms Int? - bathrooms Int? - propertyType PropertyType - status PropertyStatus @default(AVAILABLE) - isFeatured Boolean @default(false) - views Int @default(0) - - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - images Image[] - amenities PropertyAmenity[] - favorites Favorite[] - appointments Appointment[] -} - -model Image { - id String @id @default(cuid()) - url String - propertyId String - createdAt DateTime @default(now()) - - property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade) -} - -model Amenity { - id String @id @default(cuid()) - name String @unique - icon String? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - properties PropertyAmenity[] -} - -model PropertyAmenity { - propertyId String - amenityId String - - property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade) - amenity Amenity @relation(fields: [amenityId], references: [id], onDelete: Cascade) - - @@id([propertyId, amenityId]) -} - -model Favorite { - userId String - propertyId String - createdAt DateTime @default(now()) - - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade) - - @@id([userId, propertyId]) -} - -model Message { - id String @id @default(cuid()) - content String @db.Text - createdAt DateTime @default(now()) - senderId String - receiverId String - isRead Boolean @default(false) - - sender User @relation("UserMessages", fields: [senderId], references: [id], onDelete: Cascade) - receiver User @relation("ReceivedMessages", fields: [receiverId], references: [id], onDelete: Cascade) -} - -model Appointment { - id String @id @default(cuid()) - date DateTime - status AppointmentStatus @default(PENDING) - notes String? @db.Text - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - userId String - hostId String - propertyId String - - user User @relation("UserAppointments", fields: [userId], references: [id], onDelete: Cascade) - host User @relation("HostAppointments", fields: [hostId], references: [id], onDelete: Cascade) - property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade) -} - -enum Role { - USER - HOST - ADMIN -} - -enum PropertyType { - ROOM - APARTMENT - HOUSE - STUDIO - SHARED -} - -enum PropertyStatus { - AVAILABLE - RENTED - HIDDEN -} - -enum AppointmentStatus { - PENDING - CONFIRMED - CANCELLED - COMPLETED -} \ No newline at end of file diff --git a/prisma/seed.js b/prisma/seed.js deleted file mode 100644 index 8a3f018..0000000 --- a/prisma/seed.js +++ /dev/null @@ -1,136 +0,0 @@ -const { PrismaClient } = require('@prisma/client'); - -const prisma = new PrismaClient(); - -async function main() { - // Xóa dữ liệu cũ - await prisma.image.deleteMany(); - await prisma.listing.deleteMany(); - - // Tạo user mẫu - const user = await prisma.user.create({ - data: { - name: "Admin", - email: "admin@rentify.com", - image: "/images/placeholder.jpg" - } - }); - - // Tạo phòng trọ 1 - const listing1 = await prisma.listing.create({ - data: { - title: "Phòng trọ cao cấp gần Đại học Bách Khoa", - description: "Phòng trọ mới xây, đầy đủ nội thất, có ban công, cửa sổ thoáng mát. Vị trí trung tâm, thuận tiện di chuyển.", - imageSrc: "/images/rooms/room1.jpg", - price: 3000000, - area: 25, - type: "STUDIO", - bedrooms: 1, - bathrooms: 1, - roomCount: 1, - bathroomCount: 1, - amenities: ["Máy lạnh", "Tủ lạnh", "Máy giặt", "Nội thất", "Ban công", "Cửa sổ", "Bảo vệ 24/7"], - utilities: ["Điện", "Nước", "Internet"], - locationValue: "Hai Bà Trưng, Hà Nội", - address: "123 Hai Bà Trưng, Hà Nội", - phone: "0123456789", - latitude: 21.007529, - longitude: 105.847280, - userId: user.id, - images: { - create: [ - { - url: "/images/rooms/room1.jpg", - publicId: "room1" - }, - { - url: "/images/rooms/room1-2.jpg", - publicId: "room1-2" - } - ] - } - } - }); - - // Tạo phòng trọ 2 - const listing2 = await prisma.listing.create({ - data: { - title: "Căn hộ mini full nội thất khu vực Cầu Giấy", - description: "Căn hộ mini cao cấp, đầy đủ tiện nghi, an ninh 24/7, gần các trung tâm thương mại và văn phòng.", - imageSrc: "/images/rooms/room2.jpg", - price: 5500000, - area: 35, - type: "APARTMENT", - bedrooms: 1, - bathrooms: 1, - roomCount: 2, - bathroomCount: 1, - amenities: ["Full nội thất", "Máy lạnh", "Tủ lạnh", "Máy giặt", "Bếp", "Ban công", "Thang máy"], - utilities: ["Điện", "Nước", "Internet", "Dọn vệ sinh"], - locationValue: "Cầu Giấy, Hà Nội", - address: "456 Cầu Giấy, Hà Nội", - phone: "0987654321", - latitude: 21.031887, - longitude: 105.799034, - userId: user.id, - images: { - create: [ - { - url: "/images/rooms/room2.jpg", - publicId: "room2" - }, - { - url: "/images/rooms/room2-2.jpg", - publicId: "room2-2" - } - ] - } - } - }); - - // Tạo phòng trọ 3 - const listing3 = await prisma.listing.create({ - data: { - title: "Phòng trọ mới xây có gác lửng, ban công", - description: "Phòng trọ mới xây 100%, thiết kế hiện đại, có gác lửng rộng rãi, ban công thoáng mát.", - imageSrc: "/images/rooms/room3.jpg", - price: 2500000, - area: 20, - type: "ROOM", - bedrooms: 1, - bathrooms: 1, - roomCount: 1, - bathroomCount: 1, - amenities: ["Gác lửng", "Ban công", "Tủ quần áo", "Máy lạnh", "Camera an ninh", "Wifi miễn phí"], - utilities: ["Điện", "Nước", "Internet"], - locationValue: "Bình Thạnh, TP. Hồ Chí Minh", - address: "456 Xô Viết Nghệ Tĩnh, Bình Thạnh, TP. Hồ Chí Minh", - phone: "0909123456", - latitude: 10.801660, - longitude: 106.709498, - userId: user.id, - images: { - create: [ - { - url: "/images/rooms/room3.jpg", - publicId: "room3" - }, - { - url: "/images/rooms/room3-2.jpg", - publicId: "room3-2" - } - ] - } - } - }); - console.log('Đã tạo xong dữ liệu mẫu:', { listing1, listing2, listing3 }); -} - -main() - .catch((e) => { - console.error(e); - process.exit(1); - }) - .finally(async () => { - await prisma.$disconnect(); - }); \ No newline at end of file diff --git a/tatus b/tatus deleted file mode 100644 index e2f63be..0000000 --- a/tatus +++ /dev/null @@ -1,2 +0,0 @@ -* UI/UXsignin&&out - main