Sửa lỗi giao diện
This commit is contained in:
+48
-39
@@ -1,69 +1,78 @@
|
||||
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';
|
||||
|
||||
interface LandingPageProps {
|
||||
onContinue?: () => 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);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen w-full flex-col md:flex-row overflow-hidden font-sans relative">
|
||||
{/* Nửa bên trái: Ảnh background mặc định của dự án */}
|
||||
<div className="hidden md:block md:w-1/2 relative bg-gray-900">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1503220317375-aaad61436b1b?q=80&w=2070&auto=format&fit=crop"
|
||||
alt="Travel Planner Background"
|
||||
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 className="flex h-screen w-full flex-col md:flex-row overflow-hidden font-sans bg-gray-50">
|
||||
{/* Nửa bên trái: Hiển thị lưới ảnh du lịch */}
|
||||
<div className="hidden md:grid md:w-1/2 grid-cols-2 gap-2 p-2 bg-gray-200 relative h-full">
|
||||
<div className="space-y-2 h-full">
|
||||
<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" />
|
||||
<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" />
|
||||
</div>
|
||||
<span className="text-3xl font-black tracking-tighter uppercase">Travel Planner</span>
|
||||
</div>
|
||||
<h2 className="text-5xl font-bold leading-tight max-w-lg">
|
||||
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 className="space-y-2 mt-8 h-full">
|
||||
<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" />
|
||||
<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" />
|
||||
</div>
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-transparent to-gray-50/50 pointer-events-none" />
|
||||
</div>
|
||||
|
||||
{/* 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="space-y-6">
|
||||
<h1 className="text-4xl md:text-5xl font-extrabold text-gray-900 leading-tight">
|
||||
Chào mừng bạn đến với trang tạo kế hoạch du lịch
|
||||
<div className="flex items-center gap-3 text-blue-600 mb-8">
|
||||
<Compass className="w-10 h-10" />
|
||||
<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>
|
||||
<p className="text-xl text-gray-600 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ẻ.
|
||||
<p className="text-lg text-gray-500 leading-relaxed">
|
||||
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>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
{/* Nút Đăng nhập */}
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{/* Nút Khám phá Bản đồ (Cho khách công cộng) */}
|
||||
<button
|
||||
onClick={() => setIsLoginModalOpen(true)}
|
||||
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"
|
||||
onClick={onGoToMap}
|
||||
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" />
|
||||
Đăng nhập ngay
|
||||
<MapIcon className="w-5 h-5" />
|
||||
Xem Bản đồ Công cộng
|
||||
</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
|
||||
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
|
||||
<ArrowRight className="w-5 h-5" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@layer base {
|
||||
html, body, #root, .app-container {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Travel Planner</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard extends AuthGuard('jwt') {}
|
||||
@@ -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;
|
||||
Generated
+399
@@ -27,17 +27,35 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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/pg": "^8.10.0",
|
||||
"@types/react": "^18.3.12",
|
||||
"@vitejs/plugin-react": "^6.0.2",
|
||||
"autoprefixer": "^10.5.0",
|
||||
"postcss": "^8.5.15",
|
||||
"prisma": "^7.8.0",
|
||||
"tailwindcss": "^4.3.1",
|
||||
"tsx": "^4.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"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": {
|
||||
"version": "17.3.11",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.11.tgz",
|
||||
@@ -886,6 +904,17 @@
|
||||
"@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": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
@@ -1808,6 +1837,301 @@
|
||||
"devOptional": true,
|
||||
"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": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz",
|
||||
@@ -1842,6 +2166,16 @@
|
||||
"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": {
|
||||
"version": "9.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
|
||||
@@ -2332,6 +2666,43 @@
|
||||
"dev": true,
|
||||
"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": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
|
||||
@@ -3744,6 +4115,20 @@
|
||||
"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": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
|
||||
@@ -5461,6 +5846,13 @@
|
||||
"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": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz",
|
||||
@@ -6407,6 +6799,13 @@
|
||||
"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": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
|
||||
|
||||
+10
-5
@@ -2,6 +2,7 @@
|
||||
"name": "travel-planning-backend",
|
||||
"version": "1.0.0",
|
||||
"description": "Travel Planning Backend with NestJS and Prisma 7",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"start": "nest start",
|
||||
@@ -19,25 +20,29 @@
|
||||
"@prisma/client": "^7.8.0",
|
||||
"date-fns": "^2.30.0",
|
||||
"dotenv": "^16.3.0",
|
||||
"leaflet": "^1.9.4",
|
||||
"lucide-react": "^0.284.0",
|
||||
"pg": "^8.11.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-leaflet": "^4.2.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.1",
|
||||
"zustand": "^5.0.1",
|
||||
"leaflet": "^1.9.4",
|
||||
"react-leaflet": "^4.2.1"
|
||||
"zustand": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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/pg": "^8.10.0",
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/leaflet": "^1.9.12",
|
||||
"@vitejs/plugin-react": "^6.0.2",
|
||||
"@types/bcrypt": "^5.0.2",
|
||||
"autoprefixer": "^10.5.0",
|
||||
"postcss": "^8.5.15",
|
||||
"prisma": "^7.8.0",
|
||||
"tailwindcss": "^4.3.1",
|
||||
"tsx": "^4.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^8.0.16"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
"@tailwindcss/postcss": {},
|
||||
"autoprefixer": {},
|
||||
},
|
||||
}
|
||||
@@ -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
@@ -1,6 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"ignoreDeprecations": "6.0",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"allowImportingTsExtensions": true,
|
||||
"rewriteRelativeImportExtensions": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
@@ -10,7 +15,6 @@
|
||||
"target": "ES2021",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false,
|
||||
|
||||
Reference in New Issue
Block a user