email
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
hardik 2025-10-08 09:40:05 +00:00
parent f698c10cd3
commit 11ce19c59d
15 changed files with 6257 additions and 200 deletions

4
.env Normal file
View File

@ -0,0 +1,4 @@
VITE_RESEND_API_KEY=re_hCWjNNNZ_BNQ5aSKTT6DDJDvwN5v3QCSv
ZOHO_EMAIL=bookme@sangwaritaxi.com
ZOHO_PASSWORD=7qN53AdTPT1N

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ node_modules/
# Ignore build output # Ignore build output
build/ build/
.vercel

2899
node_modules/.package-lock.json generated vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,85 +1,85 @@
{ {
"hash": "c02a7a04", "hash": "6da8a140",
"configHash": "d36eeadb", "configHash": "d36eeadb",
"lockfileHash": "71693085", "lockfileHash": "9b1da6e3",
"browserHash": "c81fa583", "browserHash": "c29e10de",
"optimized": { "optimized": {
"react/jsx-dev-runtime": { "react/jsx-dev-runtime": {
"src": "../../react/jsx-dev-runtime.js", "src": "../../react/jsx-dev-runtime.js",
"file": "react_jsx-dev-runtime.js", "file": "react_jsx-dev-runtime.js",
"fileHash": "96507cc9", "fileHash": "a234d627",
"needsInterop": true "needsInterop": true
}, },
"@radix-ui/react-label": { "@radix-ui/react-label": {
"src": "../../@radix-ui/react-label/dist/index.mjs", "src": "../../@radix-ui/react-label/dist/index.mjs",
"file": "@radix-ui_react-label.js", "file": "@radix-ui_react-label.js",
"fileHash": "cd4d4396", "fileHash": "ac69cd48",
"needsInterop": false "needsInterop": false
}, },
"@radix-ui/react-select": { "@radix-ui/react-select": {
"src": "../../@radix-ui/react-select/dist/index.mjs", "src": "../../@radix-ui/react-select/dist/index.mjs",
"file": "@radix-ui_react-select.js", "file": "@radix-ui_react-select.js",
"fileHash": "e3bccc02", "fileHash": "d1e90438",
"needsInterop": false "needsInterop": false
}, },
"@radix-ui/react-separator": { "@radix-ui/react-separator": {
"src": "../../@radix-ui/react-separator/dist/index.mjs", "src": "../../@radix-ui/react-separator/dist/index.mjs",
"file": "@radix-ui_react-separator.js", "file": "@radix-ui_react-separator.js",
"fileHash": "cccdf600", "fileHash": "211b7b5a",
"needsInterop": false "needsInterop": false
}, },
"@radix-ui/react-slot": { "@radix-ui/react-slot": {
"src": "../../@radix-ui/react-slot/dist/index.mjs", "src": "../../@radix-ui/react-slot/dist/index.mjs",
"file": "@radix-ui_react-slot.js", "file": "@radix-ui_react-slot.js",
"fileHash": "5a67462b", "fileHash": "2170f3d2",
"needsInterop": false "needsInterop": false
}, },
"class-variance-authority": { "class-variance-authority": {
"src": "../../class-variance-authority/dist/index.mjs", "src": "../../class-variance-authority/dist/index.mjs",
"file": "class-variance-authority.js", "file": "class-variance-authority.js",
"fileHash": "8de36a40", "fileHash": "ec7350c2",
"needsInterop": false "needsInterop": false
}, },
"clsx": { "clsx": {
"src": "../../clsx/dist/clsx.mjs", "src": "../../clsx/dist/clsx.mjs",
"file": "clsx.js", "file": "clsx.js",
"fileHash": "2471cc19", "fileHash": "abf6854e",
"needsInterop": false "needsInterop": false
}, },
"lucide-react": { "lucide-react": {
"src": "../../lucide-react/dist/esm/lucide-react.js", "src": "../../lucide-react/dist/esm/lucide-react.js",
"file": "lucide-react.js", "file": "lucide-react.js",
"fileHash": "c54e7541", "fileHash": "40a86d41",
"needsInterop": false "needsInterop": false
}, },
"motion/react": { "motion/react": {
"src": "../../motion/dist/es/react.mjs", "src": "../../motion/dist/es/react.mjs",
"file": "motion_react.js", "file": "motion_react.js",
"fileHash": "6aab3a22", "fileHash": "702dc114",
"needsInterop": false "needsInterop": false
}, },
"react": { "react": {
"src": "../../react/index.js", "src": "../../react/index.js",
"file": "react.js", "file": "react.js",
"fileHash": "33971b8d", "fileHash": "1a08a00e",
"needsInterop": true "needsInterop": true
}, },
"react-dom/client": { "react-dom/client": {
"src": "../../react-dom/client.js", "src": "../../react-dom/client.js",
"file": "react-dom_client.js", "file": "react-dom_client.js",
"fileHash": "72f46ec7", "fileHash": "345d9e3c",
"needsInterop": true "needsInterop": true
}, },
"react/jsx-runtime": { "react/jsx-runtime": {
"src": "../../react/jsx-runtime.js", "src": "../../react/jsx-runtime.js",
"file": "react_jsx-runtime.js", "file": "react_jsx-runtime.js",
"fileHash": "e468f34f", "fileHash": "bfc11499",
"needsInterop": true "needsInterop": true
}, },
"tailwind-merge": { "tailwind-merge": {
"src": "../../tailwind-merge/dist/bundle-mjs.mjs", "src": "../../tailwind-merge/dist/bundle-mjs.mjs",
"file": "tailwind-merge.js", "file": "tailwind-merge.js",
"fileHash": "165b6bce", "fileHash": "497bb95d",
"needsInterop": false "needsInterop": false
} }
}, },

2
node_modules/@types/node/README.md generated vendored
View File

@ -8,7 +8,7 @@ This package contains type definitions for node (https://nodejs.org/).
Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node/v20. Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node/v20.
### Additional Details ### Additional Details
* Last updated: Thu, 18 Sep 2025 00:04:03 GMT * Last updated: Tue, 30 Sep 2025 23:32:16 GMT
* Dependencies: [undici-types](https://npmjs.com/package/undici-types) * Dependencies: [undici-types](https://npmjs.com/package/undici-types)
# Credits # Credits

18
node_modules/@types/node/assert.d.ts generated vendored
View File

@ -11,6 +11,24 @@ declare module "assert" {
*/ */
function assert(value: unknown, message?: string | Error): asserts value; function assert(value: unknown, message?: string | Error): asserts value;
namespace assert { namespace assert {
type AssertMethodNames =
| "deepEqual"
| "deepStrictEqual"
| "doesNotMatch"
| "doesNotReject"
| "doesNotThrow"
| "equal"
| "fail"
| "ifError"
| "match"
| "notDeepEqual"
| "notDeepStrictEqual"
| "notEqual"
| "notStrictEqual"
| "ok"
| "rejects"
| "strictEqual"
| "throws";
/** /**
* Indicates the failure of an assertion. All errors thrown by the `node:assert` module will be instances of the `AssertionError` class. * Indicates the failure of an assertion. All errors thrown by the `node:assert` module will be instances of the `AssertionError` class.
*/ */

112
node_modules/@types/node/events.d.ts generated vendored
View File

@ -36,39 +36,6 @@
*/ */
declare module "events" { declare module "events" {
import { AsyncResource, AsyncResourceOptions } from "node:async_hooks"; import { AsyncResource, AsyncResourceOptions } from "node:async_hooks";
// NOTE: This class is in the docs but is **not actually exported** by Node.
// If https://github.com/nodejs/node/issues/39903 gets resolved and Node
// actually starts exporting the class, uncomment below.
// import { EventListener, EventListenerObject } from '__dom-events';
// /** The NodeEventTarget is a Node.js-specific extension to EventTarget that emulates a subset of the EventEmitter API. */
// interface NodeEventTarget extends EventTarget {
// /**
// * Node.js-specific extension to the `EventTarget` class that emulates the equivalent `EventEmitter` API.
// * The only difference between `addListener()` and `addEventListener()` is that addListener() will return a reference to the EventTarget.
// */
// addListener(type: string, listener: EventListener | EventListenerObject, options?: { once: boolean }): this;
// /** Node.js-specific extension to the `EventTarget` class that returns an array of event `type` names for which event listeners are registered. */
// eventNames(): string[];
// /** Node.js-specific extension to the `EventTarget` class that returns the number of event listeners registered for the `type`. */
// listenerCount(type: string): number;
// /** Node.js-specific alias for `eventTarget.removeListener()`. */
// off(type: string, listener: EventListener | EventListenerObject): this;
// /** Node.js-specific alias for `eventTarget.addListener()`. */
// on(type: string, listener: EventListener | EventListenerObject, options?: { once: boolean }): this;
// /** Node.js-specific extension to the `EventTarget` class that adds a `once` listener for the given event `type`. This is equivalent to calling `on` with the `once` option set to `true`. */
// once(type: string, listener: EventListener | EventListenerObject): this;
// /**
// * Node.js-specific extension to the `EventTarget` class.
// * If `type` is specified, removes all registered listeners for `type`,
// * otherwise removes all registered listeners.
// */
// removeAllListeners(type: string): this;
// /**
// * Node.js-specific extension to the `EventTarget` class that removes the listener for the given `type`.
// * The only difference between `removeListener()` and `removeEventListener()` is that `removeListener()` will return a reference to the `EventTarget`.
// */
// removeListener(type: string, listener: EventListener | EventListenerObject): this;
// }
interface EventEmitterOptions { interface EventEmitterOptions {
/** /**
* Enables automatic capturing of promise rejection. * Enables automatic capturing of promise rejection.
@ -585,6 +552,85 @@ declare module "events" {
*/ */
readonly asyncResource: EventEmitterReferencingAsyncResource; readonly asyncResource: EventEmitterReferencingAsyncResource;
} }
/**
* The `NodeEventTarget` is a Node.js-specific extension to `EventTarget`
* that emulates a subset of the `EventEmitter` API.
* @since v14.5.0
*/
export interface NodeEventTarget extends EventTarget {
/**
* Node.js-specific extension to the `EventTarget` class that emulates the
* equivalent `EventEmitter` API. The only difference between `addListener()` and
* `addEventListener()` is that `addListener()` will return a reference to the
* `EventTarget`.
* @since v14.5.0
*/
addListener(type: string, listener: (arg: any) => void): this;
/**
* Node.js-specific extension to the `EventTarget` class that dispatches the
* `arg` to the list of handlers for `type`.
* @since v15.2.0
* @returns `true` if event listeners registered for the `type` exist,
* otherwise `false`.
*/
emit(type: string, arg: any): boolean;
/**
* Node.js-specific extension to the `EventTarget` class that returns an array
* of event `type` names for which event listeners are registered.
* @since 14.5.0
*/
eventNames(): string[];
/**
* Node.js-specific extension to the `EventTarget` class that returns the number
* of event listeners registered for the `type`.
* @since v14.5.0
*/
listenerCount(type: string): number;
/**
* Node.js-specific extension to the `EventTarget` class that sets the number
* of max event listeners as `n`.
* @since v14.5.0
*/
setMaxListeners(n: number): void;
/**
* Node.js-specific extension to the `EventTarget` class that returns the number
* of max event listeners.
* @since v14.5.0
*/
getMaxListeners(): number;
/**
* Node.js-specific alias for `eventTarget.removeEventListener()`.
* @since v14.5.0
*/
off(type: string, listener: (arg: any) => void, options?: EventListenerOptions): this;
/**
* Node.js-specific alias for `eventTarget.addEventListener()`.
* @since v14.5.0
*/
on(type: string, listener: (arg: any) => void): this;
/**
* Node.js-specific extension to the `EventTarget` class that adds a `once`
* listener for the given event `type`. This is equivalent to calling `on`
* with the `once` option set to `true`.
* @since v14.5.0
*/
once(type: string, listener: (arg: any) => void): this;
/**
* Node.js-specific extension to the `EventTarget` class. If `type` is specified,
* removes all registered listeners for `type`, otherwise removes all registered
* listeners.
* @since v14.5.0
*/
removeAllListeners(type?: string): this;
/**
* Node.js-specific extension to the `EventTarget` class that removes the
* `listener` for the given `type`. The only difference between `removeListener()`
* and `removeEventListener()` is that `removeListener()` will return a reference
* to the `EventTarget`.
* @since v14.5.0
*/
removeListener(type: string, listener: (arg: any) => void, options?: EventListenerOptions): this;
}
} }
global { global {
namespace NodeJS { namespace NodeJS {

View File

@ -1,6 +1,6 @@
{ {
"name": "@types/node", "name": "@types/node",
"version": "20.19.17", "version": "20.19.19",
"description": "TypeScript definitions for node", "description": "TypeScript definitions for node",
"homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node", "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node",
"license": "MIT", "license": "MIT",
@ -135,6 +135,6 @@
"undici-types": "~6.21.0" "undici-types": "~6.21.0"
}, },
"peerDependencies": {}, "peerDependencies": {},
"typesPublisherContentHash": "18a95350e2e7399cc51ac86ea7180283f82d3faf51d4545bc9de4d0e79a6395d", "typesPublisherContentHash": "f137b9afbfbc3918867ab07269ee57c43fa45f74d9054590bed60377448b37ef",
"typeScriptVersion": "5.2" "typeScriptVersion": "5.2"
} }

24
node_modules/@types/node/test.d.ts generated vendored
View File

@ -79,6 +79,7 @@
* @see [source](https://github.com/nodejs/node/blob/v20.13.1/lib/test.js) * @see [source](https://github.com/nodejs/node/blob/v20.13.1/lib/test.js)
*/ */
declare module "node:test" { declare module "node:test" {
import { AssertMethodNames } from "node:assert";
import { Readable } from "node:stream"; import { Readable } from "node:stream";
import TestFn = test.TestFn; import TestFn = test.TestFn;
import TestOptions = test.TestOptions; import TestOptions = test.TestOptions;
@ -933,28 +934,7 @@ declare module "node:test" {
*/ */
readonly mock: MockTracker; readonly mock: MockTracker;
} }
interface TestContextAssert extends interface TestContextAssert extends Pick<typeof import("assert"), AssertMethodNames> {}
Pick<
typeof import("assert"),
| "deepEqual"
| "deepStrictEqual"
| "doesNotMatch"
| "doesNotReject"
| "doesNotThrow"
| "equal"
| "fail"
| "ifError"
| "match"
| "notDeepEqual"
| "notDeepStrictEqual"
| "notEqual"
| "notStrictEqual"
| "ok"
| "rejects"
| "strictEqual"
| "throws"
>
{}
/** /**
* An instance of `SuiteContext` is passed to each suite function in order to * An instance of `SuiteContext` is passed to each suite function in order to
* interact with the test runner. However, the `SuiteContext` constructor is not * interact with the test runner. However, the `SuiteContext` constructor is not

View File

@ -51,6 +51,7 @@ interface EventListenerObject {
handleEvent(object: Event): void; handleEvent(object: Event): void;
} }
type _EventListenerOptions = typeof globalThis extends { onmessage: any } ? {} : EventListenerOptions;
interface EventListenerOptions { interface EventListenerOptions {
capture?: boolean; capture?: boolean;
} }
@ -85,6 +86,8 @@ declare global {
new(type: string, eventInitDict?: EventInit): Event; new(type: string, eventInitDict?: EventInit): Event;
}; };
interface EventListenerOptions extends _EventListenerOptions {}
interface EventTarget extends _EventTarget {} interface EventTarget extends _EventTarget {}
var EventTarget: typeof globalThis extends { onmessage: any; EventTarget: infer T } ? T var EventTarget: typeof globalThis extends { onmessage: any; EventTarget: infer T } ? T
: { : {

View File

@ -53,7 +53,7 @@
*/ */
declare module "worker_threads" { declare module "worker_threads" {
import { Context } from "node:vm"; import { Context } from "node:vm";
import { EventEmitter } from "node:events"; import { EventEmitter, NodeEventTarget } from "node:events";
import { EventLoopUtilityFunction } from "node:perf_hooks"; import { EventLoopUtilityFunction } from "node:perf_hooks";
import { FileHandle } from "node:fs/promises"; import { FileHandle } from "node:fs/promises";
import { Readable, Writable } from "node:stream"; import { Readable, Writable } from "node:stream";
@ -106,7 +106,7 @@ declare module "worker_threads" {
* This implementation matches [browser `MessagePort`](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort) s. * This implementation matches [browser `MessagePort`](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort) s.
* @since v10.5.0 * @since v10.5.0
*/ */
class MessagePort extends EventEmitter { class MessagePort implements EventTarget {
/** /**
* Disables further sending of messages on either side of the connection. * Disables further sending of messages on either side of the connection.
* This method can be called when no further communication will happen over this `MessagePort`. * This method can be called when no further communication will happen over this `MessagePort`.
@ -214,42 +214,32 @@ declare module "worker_threads" {
* @since v10.5.0 * @since v10.5.0
*/ */
start(): void; start(): void;
addListener(event: "close", listener: () => void): this; addListener(event: "close", listener: (ev: Event) => void): this;
addListener(event: "message", listener: (value: any) => void): this; addListener(event: "message", listener: (value: any) => void): this;
addListener(event: "messageerror", listener: (error: Error) => void): this; addListener(event: "messageerror", listener: (error: Error) => void): this;
addListener(event: string | symbol, listener: (...args: any[]) => void): this; addListener(event: string, listener: (arg: any) => void): this;
emit(event: "close"): boolean; emit(event: "close", ev: Event): boolean;
emit(event: "message", value: any): boolean; emit(event: "message", value: any): boolean;
emit(event: "messageerror", error: Error): boolean; emit(event: "messageerror", error: Error): boolean;
emit(event: string | symbol, ...args: any[]): boolean; emit(event: string, arg: any): boolean;
on(event: "close", listener: () => void): this; off(event: "close", listener: (ev: Event) => void, options?: EventListenerOptions): this;
off(event: "message", listener: (value: any) => void, options?: EventListenerOptions): this;
off(event: "messageerror", listener: (error: Error) => void, options?: EventListenerOptions): this;
off(event: string, listener: (arg: any) => void, options?: EventListenerOptions): this;
on(event: "close", listener: (ev: Event) => void): this;
on(event: "message", listener: (value: any) => void): this; on(event: "message", listener: (value: any) => void): this;
on(event: "messageerror", listener: (error: Error) => void): this; on(event: "messageerror", listener: (error: Error) => void): this;
on(event: string | symbol, listener: (...args: any[]) => void): this; on(event: string, listener: (arg: any) => void): this;
once(event: "close", listener: () => void): this; once(event: "close", listener: (ev: Event) => void): this;
once(event: "message", listener: (value: any) => void): this; once(event: "message", listener: (value: any) => void): this;
once(event: "messageerror", listener: (error: Error) => void): this; once(event: "messageerror", listener: (error: Error) => void): this;
once(event: string | symbol, listener: (...args: any[]) => void): this; once(event: string, listener: (arg: any) => void): this;
prependListener(event: "close", listener: () => void): this; removeListener(event: "close", listener: (ev: Event) => void, options?: EventListenerOptions): this;
prependListener(event: "message", listener: (value: any) => void): this; removeListener(event: "message", listener: (value: any) => void, options?: EventListenerOptions): this;
prependListener(event: "messageerror", listener: (error: Error) => void): this; removeListener(event: "messageerror", listener: (error: Error) => void, options?: EventListenerOptions): this;
prependListener(event: string | symbol, listener: (...args: any[]) => void): this; removeListener(event: string, listener: (arg: any) => void, options?: EventListenerOptions): this;
prependOnceListener(event: "close", listener: () => void): this;
prependOnceListener(event: "message", listener: (value: any) => void): this;
prependOnceListener(event: "messageerror", listener: (error: Error) => void): this;
prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;
removeListener(event: "close", listener: () => void): this;
removeListener(event: "message", listener: (value: any) => void): this;
removeListener(event: "messageerror", listener: (error: Error) => void): this;
removeListener(event: string | symbol, listener: (...args: any[]) => void): this;
off(event: "close", listener: () => void): this;
off(event: "message", listener: (value: any) => void): this;
off(event: "messageerror", listener: (error: Error) => void): this;
off(event: string | symbol, listener: (...args: any[]) => void): this;
addEventListener: EventTarget["addEventListener"];
dispatchEvent: EventTarget["dispatchEvent"];
removeEventListener: EventTarget["removeEventListener"];
} }
interface MessagePort extends NodeEventTarget {}
interface WorkerOptions { interface WorkerOptions {
/** /**
* List of arguments which would be stringified and appended to * List of arguments which would be stringified and appended to
@ -418,24 +408,6 @@ declare module "worker_threads" {
* @since v10.5.0 * @since v10.5.0
*/ */
postMessage(value: any, transferList?: readonly Transferable[]): void; postMessage(value: any, transferList?: readonly Transferable[]): void;
/**
* Sends a value to another worker, identified by its thread ID.
* @param threadId The target thread ID. If the thread ID is invalid, a `ERR_WORKER_MESSAGING_FAILED` error will be thrown.
* If the target thread ID is the current thread ID, a `ERR_WORKER_MESSAGING_SAME_THREAD` error will be thrown.
* @param value The value to send.
* @param transferList If one or more `MessagePort`-like objects are passed in value, a `transferList` is required for those items
* or `ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST` is thrown. See `port.postMessage()` for more information.
* @param timeout Time to wait for the message to be delivered in milliseconds. By default it's `undefined`, which means wait forever.
* If the operation times out, a `ERR_WORKER_MESSAGING_TIMEOUT` error is thrown.
* @since v20.19.0
*/
postMessageToThread(threadId: number, value: any, timeout?: number): Promise<void>;
postMessageToThread(
threadId: number,
value: any,
transferList: readonly Transferable[],
timeout?: number,
): Promise<void>;
/** /**
* Opposite of `unref()`, calling `ref()` on a previously `unref()`ed worker does _not_ let the program exit if it's the only active handle left (the default * Opposite of `unref()`, calling `ref()` on a previously `unref()`ed worker does _not_ let the program exit if it's the only active handle left (the default
* behavior). If the worker is `ref()`ed, calling `ref()` again has * behavior). If the worker is `ref()`ed, calling `ref()` again has

3208
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,7 @@
"@radix-ui/react-toggle": "^1.1.2", "@radix-ui/react-toggle": "^1.1.2",
"@radix-ui/react-toggle-group": "^1.1.2", "@radix-ui/react-toggle-group": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.8", "@radix-ui/react-tooltip": "^1.1.8",
"@vercel/node": "^5.3.26",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "*", "clsx": "*",
"cmdk": "^1.1.1", "cmdk": "^1.1.1",
@ -39,6 +40,7 @@
"lucide-react": "^0.487.0", "lucide-react": "^0.487.0",
"motion": "*", "motion": "*",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"nodemailer": "^7.0.9",
"react": "^18.3.1", "react": "^18.3.1",
"react-day-picker": "^8.10.1", "react-day-picker": "^8.10.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
@ -50,7 +52,8 @@
"vaul": "^1.1.2" "vaul": "^1.1.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.10.0", "@types/node": "^20.19.19",
"@types/nodemailer": "^7.0.2",
"@types/react": "^19.1.14", "@types/react": "^19.1.14",
"@types/react-dom": "^19.1.9", "@types/react-dom": "^19.1.9",
"@vitejs/plugin-react-swc": "^3.10.2", "@vitejs/plugin-react-swc": "^3.10.2",

View File

@ -2,7 +2,7 @@ import { Button } from "./ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "./ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "./ui/card";
import { Separator } from "./ui/separator"; import { Separator } from "./ui/separator";
import { Badge } from "./ui/badge"; import { Badge } from "./ui/badge";
import { CheckCircle, MapPin, Calendar, Clock, Users, Car, Phone, User } from "lucide-react"; import { CheckCircle, MapPin, Calendar, Users, Car, Phone, User } from "lucide-react";
interface BookingData { interface BookingData {
pickup: string; pickup: string;
@ -33,8 +33,49 @@ interface BookingConfirmationProps {
onEdit: () => void; onEdit: () => void;
} }
export function BookingConfirmation({ bookingData, selectedVehicle, onConfirm, onEdit }: BookingConfirmationProps) { export function BookingConfirmation({
const totalFare = selectedVehicle.price; bookingData,
selectedVehicle,
onConfirm,
onEdit,
}: BookingConfirmationProps) {
// --- POST booking data to Vercel backend ---
const handleConfirm = async () => {
try {
const res = await fetch(
"https://sangwari-backend-6fperqp5u-sangwari-taxis-projects.vercel.app/api/sendBookingEmail",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
pickup: bookingData.pickup,
dropoff: bookingData.dropoff,
date: bookingData.date,
time: bookingData.time,
passengers: bookingData.passengers,
contactName: bookingData.contactName,
contactNumber: bookingData.contactNumber,
}),
}
);
if (res.ok) {
alert("Booking email sent successfully!");
onConfirm(); // optional: trigger parent callback
} else {
const data = await res.json();
console.error("Error response:", data);
alert("Failed to send booking email.");
}
} catch (err) {
console.error("Error sending booking:", err);
alert("Error sending booking. Check console for details.");
}
};
return ( return (
<Card className="w-full max-w-2xl"> <Card className="w-full max-w-2xl">
@ -48,7 +89,6 @@ export function BookingConfirmation({ bookingData, selectedVehicle, onConfirm, o
{/* Trip Details */} {/* Trip Details */}
<div className="space-y-4"> <div className="space-y-4">
<h3>Trip Details</h3> <h3>Trip Details</h3>
<div className="grid gap-3"> <div className="grid gap-3">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<MapPin className="h-4 w-4 text-green-500" /> <MapPin className="h-4 w-4 text-green-500" />
@ -57,7 +97,6 @@ export function BookingConfirmation({ bookingData, selectedVehicle, onConfirm, o
<div>{bookingData.pickup}</div> <div>{bookingData.pickup}</div>
</div> </div>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<MapPin className="h-4 w-4 text-red-500" /> <MapPin className="h-4 w-4 text-red-500" />
<div> <div>
@ -65,7 +104,6 @@ export function BookingConfirmation({ bookingData, selectedVehicle, onConfirm, o
<div>{bookingData.dropoff}</div> <div>{bookingData.dropoff}</div>
</div> </div>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Calendar className="h-4 w-4" /> <Calendar className="h-4 w-4" />
<div> <div>
@ -73,7 +111,6 @@ export function BookingConfirmation({ bookingData, selectedVehicle, onConfirm, o
<div>{new Date(bookingData.date).toLocaleDateString()} at {bookingData.time}</div> <div>{new Date(bookingData.date).toLocaleDateString()} at {bookingData.time}</div>
</div> </div>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Users className="h-4 w-4" /> <Users className="h-4 w-4" />
<div> <div>
@ -81,7 +118,6 @@ export function BookingConfirmation({ bookingData, selectedVehicle, onConfirm, o
<div>{bookingData.passengers}</div> <div>{bookingData.passengers}</div>
</div> </div>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<User className="h-4 w-4" /> <User className="h-4 w-4" />
<div> <div>
@ -89,7 +125,6 @@ export function BookingConfirmation({ bookingData, selectedVehicle, onConfirm, o
<div>{bookingData.contactName}</div> <div>{bookingData.contactName}</div>
</div> </div>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Phone className="h-4 w-4" /> <Phone className="h-4 w-4" />
<div> <div>
@ -105,7 +140,6 @@ export function BookingConfirmation({ bookingData, selectedVehicle, onConfirm, o
{/* Vehicle Details */} {/* Vehicle Details */}
<div className="space-y-4"> <div className="space-y-4">
<h3>Selected Vehicle</h3> <h3>Selected Vehicle</h3>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center"> <div className="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center">
<Car className="h-6 w-6 text-gray-600" /> <Car className="h-6 w-6 text-gray-600" />
@ -131,16 +165,16 @@ export function BookingConfirmation({ bookingData, selectedVehicle, onConfirm, o
{/* Booking Info */} {/* Booking Info */}
<div className="space-y-4"> <div className="space-y-4">
<h3>Booking Information</h3> <h3>Booking Information</h3>
<div className="flex justify-between items-center p-4 bg-green-50 rounded-lg"> <div className="flex justify-between items-center p-4 bg-green-50 rounded-lg">
<span className="font-medium">{bookingData.dropoff.includes('Airport Taxi') ? 'Airport Taxi Fee' : 'Customize Price'}</span> <span className="font-medium">
{bookingData.dropoff.includes("Airport Taxi") ? "Airport Taxi Fee" : "Customize Price"}
</span>
<span className="text-xl font-semibold text-green-600"> <span className="text-xl font-semibold text-green-600">
{bookingData.dropoff.includes('Airport Taxi') ? '₹1099' : 'Call for Quote'} {bookingData.dropoff.includes("Airport Taxi") ? "₹1099" : "Call for Quote"}
</span> </span>
</div> </div>
<div className="text-sm text-muted-foreground text-center"> <div className="text-sm text-muted-foreground text-center">
{bookingData.dropoff.includes('Airport Taxi') {bookingData.dropoff.includes("Airport Taxi")
? `₹1099 fixed rate for airport taxi. Driver will contact you at ${bookingData.contactNumber} for pickup details.` ? `₹1099 fixed rate for airport taxi. Driver will contact you at ${bookingData.contactNumber} for pickup details.`
: `Driver will contact you at ${bookingData.contactNumber} for final pricing and trip details.`} : `Driver will contact you at ${bookingData.contactNumber} for final pricing and trip details.`}
</div> </div>
@ -151,11 +185,11 @@ export function BookingConfirmation({ bookingData, selectedVehicle, onConfirm, o
<Button variant="outline" onClick={onEdit} className="flex-1"> <Button variant="outline" onClick={onEdit} className="flex-1">
Edit Booking Edit Booking
</Button> </Button>
<Button onClick={onConfirm} className="flex-1 bg-green-600 hover:bg-green-700"> <Button onClick={handleConfirm} className="flex-1 bg-green-600 hover:bg-green-700">
Book Now Book Now
</Button> </Button>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
); );
} }

11
vite-env.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_BASE_URL: string;
readonly VITE_APP_TITLE?: string;
// Add other env variables here...
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}