Sửa lỗi giao diện

This commit is contained in:
admin committed 2026-06-13 17:02:55 +07:00
1 parent 568cb0e0bc
commit 6383965bfa
13 files changed
+568 -47

No files matched your search

+48 -39
View File
@@ -1,69 +1,78 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { LogIn, Compass, ArrowRight, Camera } from 'lucide-react'; import { LogIn, Compass, ArrowRight, Map as MapIcon, UserPlus } from 'lucide-react';
import { LoginModal } from './LoginModal'; import { LoginModal } from './LoginModal';
interface LandingPageProps { interface LandingPageProps {
onContinue?: () => void; onContinue?: () => void;
onGoToSignup?: () => void; onGoToSignup?: () => void;
onGoToMap?: () => void;
} }
export const LandingPage: React.FC<LandingPageProps> = ({ onContinue, onGoToSignup }) => { export const LandingPage: React.FC<LandingPageProps> = ({ onContinue, onGoToSignup, onGoToMap }) => {
const [isLoginModalOpen, setIsLoginModalOpen] = useState(false); const [isLoginModalOpen, setIsLoginModalOpen] = useState(false);
return ( return (
<div className="flex h-screen w-full flex-col md:flex-row overflow-hidden font-sans relative"> <div className="flex h-screen w-full flex-col md:flex-row overflow-hidden font-sans bg-gray-50">
{/* Nửa bên trái: Ảnh background mặc định của dự án */} {/* Nửa bên trái: Hiển thị lưới ảnh du lịch */}
<div className="hidden md:block md:w-1/2 relative bg-gray-900"> <div className="hidden md:grid md:w-1/2 grid-cols-2 gap-2 p-2 bg-gray-200 relative h-full">
<img <div className="space-y-2 h-full">
src="https://images.unsplash.com/photo-1503220317375-aaad61436b1b?q=80&w=2070&auto=format&fit=crop" <img src="https://images.unsplash.com/photo-1503220317375-aaad61436b1b?auto=format&fit=crop&q=80" className="w-full h-64 object-cover rounded-xl" alt="Travel 1" />
alt="Travel Planner Background" <img src="https://images.unsplash.com/photo-1513581166391-887a96df91e7?auto=format&fit=crop&q=80" className="w-full h-96 object-cover rounded-xl" alt="Travel 2" />
className="absolute inset-0 h-full w-full object-cover opacity-70"
/>
{/* Overlay màu xanh nhẹ đặc trưng của dự án */}
<div className="absolute inset-0 bg-gradient-to-t from-blue-900/60 to-transparent" />
<div className="absolute bottom-16 left-16 text-white z-10">
<div className="flex items-center gap-3 mb-6">
<div className="p-3 bg-white/20 backdrop-blur-md rounded-2xl">
<Compass className="w-8 h-8 text-white" />
</div> </div>
<span className="text-3xl font-black tracking-tighter uppercase">Travel Planner</span> <div className="space-y-2 mt-8 h-full">
</div> <img src="https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&q=80" className="w-full h-96 object-cover rounded-xl" alt="Travel 3" />
<h2 className="text-5xl font-bold leading-tight max-w-lg"> <img src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?auto=format&fit=crop&q=80" className="w-full h-64 object-cover rounded-xl" alt="Travel 4" />
Khám phá thế giới, lưu giữ kỉ niệm.
</h2>
<p className="mt-4 text-blue-100 text-lg opacity-80 max-w-sm">
Hợp tác cùng bạn bè để lên lịch trình hoàn hảo nhất cho mọi chuyến đi.
</p>
</div> </div>
<div className="absolute inset-0 bg-gradient-to-r from-transparent to-gray-50/50 pointer-events-none" />
</div> </div>
{/* Nửa bên phải: Nội dung chào mừng và Hành động */} {/* Nửa bên phải: Nội dung chào mừng và Hành động */}
<div className="flex-1 flex flex-col justify-center items-center bg-white p-8 sm:p-12 md:p-20"> <div className="flex-1 md:w-1/2 flex flex-col justify-center items-center bg-white p-8 lg:p-16 h-full overflow-y-auto">
<div className="max-w-md w-full space-y-12"> <div className="max-w-md w-full space-y-12">
<div className="space-y-6"> <div className="flex items-center gap-3 text-blue-600 mb-8">
<h1 className="text-4xl md:text-5xl font-extrabold text-gray-900 leading-tight"> <Compass className="w-10 h-10" />
Chào mừng bạn đến với trang tạo kế hoạch du lịch <span className="text-2xl font-black tracking-tighter uppercase">Travel Planner</span>
</div>
<div className="space-y-4">
<h1 className="text-4xl font-extrabold text-gray-900 leading-tight">
Lên kế hoạch cho hành trình tiếp theo
</h1> </h1>
<p className="text-xl text-gray-600 leading-relaxed"> <p className="text-lg text-gray-500 leading-relaxed">
Đăng nhập để vào tạo kế hoạch cá nhân hoặc nhấn nút tiếp tục để tham quan các hình ảnh du lịch được chia sẻ. Khám phá các địa điểm nổi bật qua bản đồ cộng đồng hoặc đăng nhập để bắt đầu tự tạo chuyến đi cho riêng mình.
</p> </p>
</div> </div>
<div className="flex flex-col gap-4"> <div className="grid grid-cols-1 gap-4">
{/* Nút Đăng nhập */} {/* Nút Khám phá Bản đồ (Cho khách công cộng) */}
<button <button
onClick={() => setIsLoginModalOpen(true)} onClick={onGoToMap}
className="group flex items-center justify-center gap-3 bg-blue-600 hover:bg-blue-700 text-white font-bold py-5 px-8 rounded-2xl shadow-xl shadow-blue-200 transition-all active:scale-95" className="flex items-center justify-center gap-3 bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-4 px-8 rounded-2xl transition-all shadow-lg shadow-indigo-100"
> >
<LogIn className="w-5 h-5 group-hover:translate-x-1 transition-transform" /> <MapIcon className="w-5 h-5" />
Đăng nhập ngay Xem Bản đồ Công cộng
</button> </button>
{/* Nút Tiếp tục */} <div className="grid grid-cols-2 gap-4">
<button
onClick={() => setIsLoginModalOpen(true)}
className="flex items-center justify-center gap-2 bg-blue-50 hover:bg-blue-100 text-blue-700 font-bold py-4 rounded-2xl transition-all"
>
<LogIn className="w-5 h-5" />
Đăng nhập
</button>
<button
onClick={onGoToSignup}
className="flex items-center justify-center gap-2 bg-gray-50 hover:bg-gray-100 text-gray-700 font-bold py-4 rounded-2xl border border-gray-100 transition-all"
>
<UserPlus className="w-5 h-5" />
Đăng ký
</button>
</div>
<button <button
onClick={onContinue} onClick={onContinue}
className="flex items-center justify-center gap-3 bg-gray-50 hover:bg-gray-100 text-gray-700 font-bold py-5 px-8 rounded-2xl border border-gray-200 transition-all active:scale-95" className="flex items-center justify-center gap-3 text-gray-400 hover:text-gray-600 py-2 transition-all text-sm font-medium"
> >
Tiếp tục tham quan ảnh Tiếp tục tham quan ảnh
<ArrowRight className="w-5 h-5" /> <ArrowRight className="w-5 h-5" />
+30
View File
@@ -0,0 +1,30 @@
import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Injectable()
export class AdminGuard implements CanActivate {
constructor(private prisma: PrismaService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
// Lưu ý: request.user thường được đính kèm bởi một AuthGuard (JWT/Passport) chạy trước đó.
const user = request.user;
if (!user || !user.id) {
throw new ForbiddenException('Yêu cầu xác thực không hợp lệ. Vui lòng đăng nhập.');
}
// Kiểm tra trực tiếp từ database để đảm bảo quyền isAdmin là chính xác nhất cho các tác vụ nhạy cảm
const dbUser = await this.prisma.user.findUnique({
where: { id: user.id },
select: { isAdmin: true },
});
if (!dbUser || !dbUser.isAdmin) {
throw new ForbiddenException('Truy cập bị từ chối. Bạn không có quyền quản trị viên hệ thống.');
}
return true;
}
}
+9
View File
@@ -0,0 +1,9 @@
@import "tailwindcss";
@layer base {
html, body, #root, .app-container {
height: 100%;
margin: 0;
padding: 0;
}
}
-1
View File
@@ -4,7 +4,6 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Travel Planner</title> <title>Travel Planner</title>
<script src="https://cdn.tailwindcss.com"></script>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
+1
View File
@@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App'; import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render( ReactDOM.createRoot(document.getElementById('root')!).render(
+5
View File
@@ -0,0 +1,5 @@
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
+27
View File
@@ -0,0 +1,27 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PrismaService } from './prisma.service';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private prisma: PrismaService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_SECRET || 'super-secret',
});
}
async validate(payload: any) {
const user = await this.prisma.user.findUnique({
where: { id: payload.sub },
});
if (!user) {
throw new UnauthorizedException('Người dùng không tồn tại hoặc phiên làm việc hết hạn');
}
return user;
}
}
@@ -0,0 +1,14 @@
-- DropForeignKey
ALTER TABLE "Expense" DROP CONSTRAINT "Expense_legId_fkey";
-- DropForeignKey
ALTER TABLE "Expense" DROP CONSTRAINT "Expense_placeId_fkey";
-- AlterTable
ALTER TABLE "User" ADD COLUMN "isAdmin" BOOLEAN NOT NULL DEFAULT false;
-- AddForeignKey
ALTER TABLE "Expense" ADD CONSTRAINT "Expense_legId_fkey" FOREIGN KEY ("legId") REFERENCES "Leg"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Expense" ADD CONSTRAINT "Expense_placeId_fkey" FOREIGN KEY ("placeId") REFERENCES "Place"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+399
View File
@@ -27,17 +27,35 @@
}, },
"devDependencies": { "devDependencies": {
"@nestjs/cli": "^10.0.0", "@nestjs/cli": "^10.0.0",
"@tailwindcss/postcss": "^4.3.1",
"@types/bcrypt": "^5.0.2",
"@types/leaflet": "^1.9.12", "@types/leaflet": "^1.9.12",
"@types/node": "^20.0.0", "@types/node": "^20.0.0",
"@types/pg": "^8.10.0", "@types/pg": "^8.10.0",
"@types/react": "^18.3.12", "@types/react": "^18.3.12",
"@vitejs/plugin-react": "^6.0.2", "@vitejs/plugin-react": "^6.0.2",
"autoprefixer": "^10.5.0",
"postcss": "^8.5.15",
"prisma": "^7.8.0", "prisma": "^7.8.0",
"tailwindcss": "^4.3.1",
"tsx": "^4.0.0", "tsx": "^4.0.0",
"typescript": "^5.0.0", "typescript": "^5.0.0",
"vite": "^8.0.16" "vite": "^8.0.16"
} }
}, },
"node_modules/@alloc/quick-lru": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@angular-devkit/core": { "node_modules/@angular-devkit/core": {
"version": "17.3.11", "version": "17.3.11",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.11.tgz", "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.11.tgz",
@@ -886,6 +904,17 @@
"@jridgewell/trace-mapping": "^0.3.24" "@jridgewell/trace-mapping": "^0.3.24"
} }
}, },
"node_modules/@jridgewell/remapping": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/resolve-uri": { "node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
@@ -1808,6 +1837,301 @@
"devOptional": true, "devOptional": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@tailwindcss/node": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.1.tgz",
"integrity": "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/remapping": "^2.3.5",
"enhanced-resolve": "5.21.6",
"jiti": "^2.7.0",
"lightningcss": "1.32.0",
"magic-string": "^0.30.21",
"source-map-js": "^1.2.1",
"tailwindcss": "4.3.1"
}
},
"node_modules/@tailwindcss/node/node_modules/enhanced-resolve": {
"version": "5.21.6",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz",
"integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.3.3"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/@tailwindcss/node/node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/@tailwindcss/oxide": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.1.tgz",
"integrity": "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 20"
},
"optionalDependencies": {
"@tailwindcss/oxide-android-arm64": "4.3.1",
"@tailwindcss/oxide-darwin-arm64": "4.3.1",
"@tailwindcss/oxide-darwin-x64": "4.3.1",
"@tailwindcss/oxide-freebsd-x64": "4.3.1",
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1",
"@tailwindcss/oxide-linux-arm64-gnu": "4.3.1",
"@tailwindcss/oxide-linux-arm64-musl": "4.3.1",
"@tailwindcss/oxide-linux-x64-gnu": "4.3.1",
"@tailwindcss/oxide-linux-x64-musl": "4.3.1",
"@tailwindcss/oxide-wasm32-wasi": "4.3.1",
"@tailwindcss/oxide-win32-arm64-msvc": "4.3.1",
"@tailwindcss/oxide-win32-x64-msvc": "4.3.1"
}
},
"node_modules/@tailwindcss/oxide-android-arm64": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.1.tgz",
"integrity": "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-darwin-arm64": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.1.tgz",
"integrity": "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-darwin-x64": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.1.tgz",
"integrity": "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-freebsd-x64": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.1.tgz",
"integrity": "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.1.tgz",
"integrity": "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.1.tgz",
"integrity": "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.1.tgz",
"integrity": "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.1.tgz",
"integrity": "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.1.tgz",
"integrity": "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.1.tgz",
"integrity": "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==",
"bundleDependencies": [
"@napi-rs/wasm-runtime",
"@emnapi/core",
"@emnapi/runtime",
"@tybys/wasm-util",
"@emnapi/wasi-threads",
"tslib"
],
"cpu": [
"wasm32"
],
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "^1.10.0",
"@emnapi/runtime": "^1.10.0",
"@emnapi/wasi-threads": "^1.2.1",
"@napi-rs/wasm-runtime": "^1.1.4",
"@tybys/wasm-util": "^0.10.2",
"tslib": "^2.8.1"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.1.tgz",
"integrity": "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.1.tgz",
"integrity": "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 20"
}
},
"node_modules/@tailwindcss/postcss": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.1.tgz",
"integrity": "sha512-dNJuNbdEJT/SWRuXTYP1WSamelsz3ztkUsdtWQPjrexysrTpaEPM40P/71knXiXLYEojqPOEGitVLLpPMS5T6A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"@tailwindcss/node": "4.3.1",
"@tailwindcss/oxide": "4.3.1",
"postcss": "8.5.15",
"tailwindcss": "4.3.1"
}
},
"node_modules/@tokenizer/inflate": { "node_modules/@tokenizer/inflate": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz",
@@ -1842,6 +2166,16 @@
"tslib": "^2.4.0" "tslib": "^2.4.0"
} }
}, },
"node_modules/@types/bcrypt": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz",
"integrity": "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/eslint": { "node_modules/@types/eslint": {
"version": "9.6.1", "version": "9.6.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
@@ -2332,6 +2666,43 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/autoprefixer": {
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz",
"integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/autoprefixer"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"browserslist": "^4.28.2",
"caniuse-lite": "^1.0.30001787",
"fraction.js": "^5.3.4",
"picocolors": "^1.1.1",
"postcss-value-parser": "^4.2.0"
},
"bin": {
"autoprefixer": "bin/autoprefixer"
},
"engines": {
"node": "^10 || ^12 || >=14"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/aws-ssl-profiles": { "node_modules/aws-ssl-profiles": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
@@ -3744,6 +4115,20 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/fraction.js": {
"version": "5.3.4",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
"integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": "*"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/rawify"
}
},
"node_modules/fresh": { "node_modules/fresh": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
@@ -5461,6 +5846,13 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/postcss-value-parser": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true,
"license": "MIT"
},
"node_modules/postgres": { "node_modules/postgres": {
"version": "3.4.7", "version": "3.4.7",
"resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz", "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz",
@@ -6407,6 +6799,13 @@
"node": ">=0.10" "node": ">=0.10"
} }
}, },
"node_modules/tailwindcss": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.1.tgz",
"integrity": "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==",
"dev": true,
"license": "MIT"
},
"node_modules/tapable": { "node_modules/tapable": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+10 -5
View File
@@ -2,6 +2,7 @@
"name": "travel-planning-backend", "name": "travel-planning-backend",
"version": "1.0.0", "version": "1.0.0",
"description": "Travel Planning Backend with NestJS and Prisma 7", "description": "Travel Planning Backend with NestJS and Prisma 7",
"type": "module",
"scripts": { "scripts": {
"build": "nest build", "build": "nest build",
"start": "nest start", "start": "nest start",
@@ -19,25 +20,29 @@
"@prisma/client": "^7.8.0", "@prisma/client": "^7.8.0",
"date-fns": "^2.30.0", "date-fns": "^2.30.0",
"dotenv": "^16.3.0", "dotenv": "^16.3.0",
"leaflet": "^1.9.4",
"lucide-react": "^0.284.0", "lucide-react": "^0.284.0",
"pg": "^8.11.0", "pg": "^8.11.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-leaflet": "^4.2.1",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1", "rxjs": "^7.8.1",
"zustand": "^5.0.1", "zustand": "^5.0.1"
"leaflet": "^1.9.4",
"react-leaflet": "^4.2.1"
}, },
"devDependencies": { "devDependencies": {
"@nestjs/cli": "^10.0.0", "@nestjs/cli": "^10.0.0",
"@tailwindcss/postcss": "^4.3.1",
"@types/bcrypt": "^5.0.2",
"@types/leaflet": "^1.9.12",
"@types/node": "^20.0.0", "@types/node": "^20.0.0",
"@types/pg": "^8.10.0", "@types/pg": "^8.10.0",
"@types/react": "^18.3.12", "@types/react": "^18.3.12",
"@types/leaflet": "^1.9.12",
"@vitejs/plugin-react": "^6.0.2", "@vitejs/plugin-react": "^6.0.2",
"@types/bcrypt": "^5.0.2", "autoprefixer": "^10.5.0",
"postcss": "^8.5.15",
"prisma": "^7.8.0", "prisma": "^7.8.0",
"tailwindcss": "^4.3.1",
"tsx": "^4.0.0", "tsx": "^4.0.0",
"typescript": "^5.0.0", "typescript": "^5.0.0",
"vite": "^8.0.16" "vite": "^8.0.16"
+6
View File
@@ -0,0 +1,6 @@
export default {
plugins: {
"@tailwindcss/postcss": {},
"autoprefixer": {},
},
}
+13
View File
@@ -0,0 +1,13 @@
import type { Config } from 'tailwindcss'
export default {
content: [
"./index.html",
"./*.{js,ts,jsx,tsx}",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
} satisfies Config
+6 -2
View File
@@ -1,6 +1,11 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "commonjs", "ignoreDeprecations": "6.0",
"module": "ESNext",
"moduleResolution": "node",
"allowImportingTsExtensions": true,
"rewriteRelativeImportExtensions": true,
"noEmit": true,
"jsx": "react-jsx", "jsx": "react-jsx",
"declaration": true, "declaration": true,
"removeComments": true, "removeComments": true,
@@ -10,7 +15,6 @@
"target": "ES2021", "target": "ES2021",
"sourceMap": true, "sourceMap": true,
"outDir": "./dist", "outDir": "./dist",
"baseUrl": "./",
"incremental": true, "incremental": true,
"skipLibCheck": true, "skipLibCheck": true,
"strictNullChecks": false, "strictNullChecks": false,