🎯 MapView v2.0 - Global Deployment Ready

 MAJOR FEATURES:
• Auto-zoom intelligence với smart bounds fitting
• Enhanced 3D GPS markers với pulsing effects
• Professional route display với 6-layer rendering
• Status-based parking icons với availability indicators
• Production-ready build optimizations

🗺️ AUTO-ZOOM FEATURES:
• Smart bounds fitting cho GPS + selected parking
• Adaptive padding (50px) cho visual balance
• Max zoom control (level 16) để tránh quá gần
• Dynamic centering khi không có selection

🎨 ENHANCED VISUALS:
• 3D GPS marker với multi-layer pulse effects
• Advanced parking icons với status colors
• Selection highlighting với animation
• Dimming system cho non-selected items

🛣️ ROUTE SYSTEM:
• OpenRouteService API integration
• Multi-layer route rendering (glow, shadow, main, animated)
• Real-time distance & duration calculation
• Visual route info trong popup

📱 PRODUCTION READY:
• SSR safe với dynamic imports
• Build errors resolved
• Global deployment via Vercel
• Optimized performance

🌍 DEPLOYMENT:
• Vercel: https://whatever-ctk2auuxr-phong12hexdockworks-projects.vercel.app
• Bundle size: 22.8 kB optimized
• Global CDN distribution
• HTTPS enabled

💾 VERSION CONTROL:
• MapView-v2.0.tsx backup created
• MAPVIEW_VERSIONS.md documentation
• Full version history tracking
This commit is contained in:
2025-07-20 19:52:16 +07:00
parent 3203463a6a
commit c65cc97a33
64624 changed files with 7199453 additions and 6462 deletions

View File

@@ -0,0 +1,24 @@
import { FileValidator } from './file-validator.interface';
import { IFile } from './interfaces';
export type FileTypeValidatorOptions = {
fileType: string | RegExp;
/**
* If `true`, the validator will skip the magic numbers validation.
* This can be useful when you can't identify some files as there are no common magic numbers available for some file types.
* @default false
*/
skipMagicNumbersValidation?: boolean;
};
/**
* Defines the built-in FileTypeValidator. It validates incoming files by examining
* their magic numbers using the file-type package, providing more reliable file type validation
* than just checking the mimetype string.
*
* @see [File Validators](https://docs.nestjs.com/techniques/file-upload#validators)
*
* @publicApi
*/
export declare class FileTypeValidator extends FileValidator<FileTypeValidatorOptions, IFile> {
buildErrorMessage(file?: IFile): string;
isValid(file?: IFile): Promise<boolean>;
}

View File

@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileTypeValidator = void 0;
const file_validator_interface_1 = require("./file-validator.interface");
/**
* Defines the built-in FileTypeValidator. It validates incoming files by examining
* their magic numbers using the file-type package, providing more reliable file type validation
* than just checking the mimetype string.
*
* @see [File Validators](https://docs.nestjs.com/techniques/file-upload#validators)
*
* @publicApi
*/
class FileTypeValidator extends file_validator_interface_1.FileValidator {
buildErrorMessage(file) {
if (file?.mimetype) {
return `Validation failed (current file type is ${file.mimetype}, expected type is ${this.validationOptions.fileType})`;
}
return `Validation failed (expected type is ${this.validationOptions.fileType})`;
}
async isValid(file) {
if (!this.validationOptions) {
return true;
}
const isFileValid = !!file && 'mimetype' in file;
if (this.validationOptions.skipMagicNumbersValidation) {
return (isFileValid && !!file.mimetype.match(this.validationOptions.fileType));
}
if (!isFileValid || !file.buffer) {
return false;
}
try {
const { fileTypeFromBuffer } = (await eval('import ("file-type")'));
const fileType = await fileTypeFromBuffer(file.buffer);
return (!!fileType && !!fileType.mime.match(this.validationOptions.fileType));
}
catch {
return false;
}
}
}
exports.FileTypeValidator = FileTypeValidator;

View File

@@ -0,0 +1,21 @@
import { IFile } from './interfaces';
/**
* Interface describing FileValidators, which can be added to a ParseFilePipe
*
* @see {ParseFilePipe}
* @publicApi
*/
export declare abstract class FileValidator<TValidationOptions = Record<string, any>, TFile extends IFile = IFile> {
protected readonly validationOptions: TValidationOptions;
constructor(validationOptions: TValidationOptions);
/**
* Indicates if this file should be considered valid, according to the options passed in the constructor.
* @param file the file from the request object
*/
abstract isValid(file?: TFile | TFile[] | Record<string, TFile[]>): boolean | Promise<boolean>;
/**
* Builds an error message in case the validation fails.
* @param file the file from the request object
*/
abstract buildErrorMessage(file: any): string;
}

View File

@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileValidator = void 0;
/**
* Interface describing FileValidators, which can be added to a ParseFilePipe
*
* @see {ParseFilePipe}
* @publicApi
*/
class FileValidator {
constructor(validationOptions) {
this.validationOptions = validationOptions;
}
}
exports.FileValidator = FileValidator;

View File

@@ -0,0 +1,6 @@
export * from './file-type.validator';
export * from './file-validator.interface';
export * from './max-file-size.validator';
export * from './parse-file-options.interface';
export * from './parse-file.pipe';
export * from './parse-file-pipe.builder';

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./file-type.validator"), exports);
tslib_1.__exportStar(require("./file-validator.interface"), exports);
tslib_1.__exportStar(require("./max-file-size.validator"), exports);
tslib_1.__exportStar(require("./parse-file-options.interface"), exports);
tslib_1.__exportStar(require("./parse-file.pipe"), exports);
tslib_1.__exportStar(require("./parse-file-pipe.builder"), exports);

View File

@@ -0,0 +1,5 @@
export interface IFile {
mimetype: string;
size: number;
buffer?: Buffer;
}

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1 @@
export * from './file.interface';

View File

@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./file.interface"), exports);

View File

@@ -0,0 +1,17 @@
import { FileValidator } from './file-validator.interface';
import { IFile } from './interfaces';
export type MaxFileSizeValidatorOptions = {
maxSize: number;
message?: string | ((maxSize: number) => string);
};
/**
* Defines the built-in MaxSize File Validator
*
* @see [File Validators](https://docs.nestjs.com/techniques/file-upload#file-validation)
*
* @publicApi
*/
export declare class MaxFileSizeValidator extends FileValidator<MaxFileSizeValidatorOptions, IFile> {
buildErrorMessage(): string;
isValid(file?: IFile): boolean;
}

View File

@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MaxFileSizeValidator = void 0;
const file_validator_interface_1 = require("./file-validator.interface");
/**
* Defines the built-in MaxSize File Validator
*
* @see [File Validators](https://docs.nestjs.com/techniques/file-upload#file-validation)
*
* @publicApi
*/
class MaxFileSizeValidator extends file_validator_interface_1.FileValidator {
buildErrorMessage() {
if ('message' in this.validationOptions) {
if (typeof this.validationOptions.message === 'function') {
return this.validationOptions.message(this.validationOptions.maxSize);
}
return this.validationOptions.message;
}
return `Validation failed (expected size is less than ${this.validationOptions.maxSize})`;
}
isValid(file) {
if (!this.validationOptions || !file) {
return true;
}
return 'size' in file && file.size < this.validationOptions.maxSize;
}
}
exports.MaxFileSizeValidator = MaxFileSizeValidator;

View File

@@ -0,0 +1,15 @@
import { ErrorHttpStatusCode } from '../../utils/http-error-by-code.util';
import { FileValidator } from './file-validator.interface';
/**
* @publicApi
*/
export interface ParseFileOptions {
validators?: FileValidator[];
errorHttpStatusCode?: ErrorHttpStatusCode;
exceptionFactory?: (error: string) => any;
/**
* Defines if file parameter is required.
* @default true
*/
fileIsRequired?: boolean;
}

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,15 @@
import { FileTypeValidatorOptions } from './file-type.validator';
import { FileValidator } from './file-validator.interface';
import { MaxFileSizeValidatorOptions } from './max-file-size.validator';
import { ParseFileOptions } from './parse-file-options.interface';
import { ParseFilePipe } from './parse-file.pipe';
/**
* @publicApi
*/
export declare class ParseFilePipeBuilder {
private validators;
addMaxSizeValidator(options: MaxFileSizeValidatorOptions): this;
addFileTypeValidator(options: FileTypeValidatorOptions): this;
addValidator(validator: FileValidator): this;
build(additionalOptions?: Omit<ParseFileOptions, 'validators'>): ParseFilePipe;
}

View File

@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ParseFilePipeBuilder = void 0;
const file_type_validator_1 = require("./file-type.validator");
const max_file_size_validator_1 = require("./max-file-size.validator");
const parse_file_pipe_1 = require("./parse-file.pipe");
/**
* @publicApi
*/
class ParseFilePipeBuilder {
constructor() {
this.validators = [];
}
addMaxSizeValidator(options) {
return this.addValidator(new max_file_size_validator_1.MaxFileSizeValidator(options));
}
addFileTypeValidator(options) {
return this.addValidator(new file_type_validator_1.FileTypeValidator(options));
}
addValidator(validator) {
this.validators.push(validator);
return this;
}
build(additionalOptions) {
const parseFilePipe = new parse_file_pipe_1.ParseFilePipe({
...additionalOptions,
validators: this.validators,
});
this.validators = [];
return parseFilePipe;
}
}
exports.ParseFilePipeBuilder = ParseFilePipeBuilder;

View File

@@ -0,0 +1,28 @@
import { PipeTransform } from '../../interfaces/features/pipe-transform.interface';
import { FileValidator } from './file-validator.interface';
import { ParseFileOptions } from './parse-file-options.interface';
/**
* Defines the built-in ParseFile Pipe. This pipe can be used to validate incoming files
* with `@UploadedFile()` decorator. You can use either other specific built-in validators
* or provide one of your own, simply implementing it through FileValidator interface
* and adding it to ParseFilePipe's constructor.
*
* @see [Built-in Pipes](https://docs.nestjs.com/pipes#built-in-pipes)
*
* @publicApi
*/
export declare class ParseFilePipe implements PipeTransform<any> {
protected exceptionFactory: (error: string) => any;
private readonly validators;
private readonly fileIsRequired;
constructor(options?: ParseFileOptions);
transform(value: any): Promise<any>;
private validateFilesOrFile;
private thereAreNoFilesIn;
protected validate(file: any): Promise<any>;
private validateOrThrow;
/**
* @returns list of validators used in this pipe.
*/
getValidators(): FileValidator<Record<string, any>, import("./interfaces").IFile>[];
}

View File

@@ -0,0 +1,76 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ParseFilePipe = void 0;
const tslib_1 = require("tslib");
const core_1 = require("../../decorators/core");
const enums_1 = require("../../enums");
const http_error_by_code_util_1 = require("../../utils/http-error-by-code.util");
const shared_utils_1 = require("../../utils/shared.utils");
/**
* Defines the built-in ParseFile Pipe. This pipe can be used to validate incoming files
* with `@UploadedFile()` decorator. You can use either other specific built-in validators
* or provide one of your own, simply implementing it through FileValidator interface
* and adding it to ParseFilePipe's constructor.
*
* @see [Built-in Pipes](https://docs.nestjs.com/pipes#built-in-pipes)
*
* @publicApi
*/
let ParseFilePipe = class ParseFilePipe {
constructor(options = {}) {
const { exceptionFactory, errorHttpStatusCode = enums_1.HttpStatus.BAD_REQUEST, validators = [], fileIsRequired, } = options;
this.exceptionFactory =
exceptionFactory ||
(error => new http_error_by_code_util_1.HttpErrorByCode[errorHttpStatusCode](error));
this.validators = validators;
this.fileIsRequired = fileIsRequired ?? true;
}
async transform(value) {
const areThereAnyFilesIn = this.thereAreNoFilesIn(value);
if (areThereAnyFilesIn && this.fileIsRequired) {
throw this.exceptionFactory('File is required');
}
if (!areThereAnyFilesIn && this.validators.length) {
await this.validateFilesOrFile(value);
}
return value;
}
async validateFilesOrFile(value) {
if (Array.isArray(value)) {
await Promise.all(value.map(f => this.validate(f)));
}
else {
await this.validate(value);
}
}
thereAreNoFilesIn(value) {
const isEmptyArray = Array.isArray(value) && (0, shared_utils_1.isEmpty)(value);
const isEmptyObject = (0, shared_utils_1.isObject)(value) && (0, shared_utils_1.isEmpty)(Object.keys(value));
return (0, shared_utils_1.isUndefined)(value) || isEmptyArray || isEmptyObject;
}
async validate(file) {
for (const validator of this.validators) {
await this.validateOrThrow(file, validator);
}
return file;
}
async validateOrThrow(file, validator) {
const isValid = await validator.isValid(file);
if (!isValid) {
const errorMessage = validator.buildErrorMessage(file);
throw this.exceptionFactory(errorMessage);
}
}
/**
* @returns list of validators used in this pipe.
*/
getValidators() {
return this.validators;
}
};
exports.ParseFilePipe = ParseFilePipe;
exports.ParseFilePipe = ParseFilePipe = tslib_1.__decorate([
(0, core_1.Injectable)(),
tslib_1.__param(0, (0, core_1.Optional)()),
tslib_1.__metadata("design:paramtypes", [Object])
], ParseFilePipe);