🎯 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,4 @@
{
"presets": ["env", "stage-0"],
"plugins": ["transform-decorators-legacy"]
}

View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"target": "ES2021",
"experimentalDecorators": true
},
"exclude": [
"node_modules"
]
}

View File

@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { <%= classify(name) %>Service } from './<%= name %>.service';
@Module({
providers: [<%= classify(name) %>Service],
exports: [<%= classify(name) %>Service],
})
export class <%= classify(name) %>Module {}

View File

@@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class <%= classify(name) %>Service {}

View File

@@ -0,0 +1,18 @@
import { Test } from '@nestjs/testing';
import { <%= classify(name) %>Service } from './<%= name %>.service';
describe('<%= classify(name) %>Service', () => {
let service;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [<%= classify(name) %>Service],
}).compile();
service = module.get(<%= classify(name) %>Service);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -0,0 +1,2 @@
export * from './<%= name %>.module';
export * from './<%= name %>.service';

View File

@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { <%= classify(name) %>Service } from './<%= name %>.service';
@Module({
providers: [<%= classify(name) %>Service],
exports: [<%= classify(name) %>Service],
})
export class <%= classify(name) %>Module {}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { <%= classify(name) %>Service } from './<%= name %>.service';
describe('<%= classify(name) %>Service', () => {
let service: <%= classify(name) %>Service;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [<%= classify(name) %>Service],
}).compile();
service = module.get<<%= classify(name) %>Service>(<%= classify(name) %>Service);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class <%= classify(name) %>Service {}

View File

@@ -0,0 +1,2 @@
export * from './<%= name %>.module';
export * from './<%= name %>.service';

View File

@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"declaration": true,
"outDir": "../../dist/libs/<%= name %>"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "test", "**/*spec.ts"]
}

View File

@@ -0,0 +1,3 @@
import { Rule } from '@angular-devkit/schematics';
import { LibraryOptions } from './library.schema';
export declare function main(options: LibraryOptions): Rule;

View File

@@ -0,0 +1,211 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.main = main;
const core_1 = require("@angular-devkit/core");
const schematics_1 = require("@angular-devkit/schematics");
const jsonc_parser_1 = require("jsonc-parser");
const formatting_1 = require("../../utils/formatting");
const defaults_1 = require("../defaults");
const readers_1 = require("../readers");
function main(options) {
options = transform(options);
return (0, schematics_1.chain)([
addLibraryToCliOptions(options.path, options.name),
updatePackageJson(options),
updateJestEndToEnd(options),
updateTsConfig(options.name, options.prefix, options.path),
(0, schematics_1.branchAndMerge)((0, schematics_1.mergeWith)(generate(options))),
]);
}
function getDefaultLibraryPrefix(defaultLibraryPrefix = '@app') {
const fileSystemReader = new readers_1.FileSystemReader(process.cwd());
const content = fileSystemReader.readSyncAnyOf([
'nest-cli.json',
'.nestcli.json',
'.nest-cli.json',
'nest.json',
]);
try {
const nestJson = JSON.parse(content || '{}');
if (nestJson.hasOwnProperty('defaultLibraryPrefix')) {
return nestJson['defaultLibraryPrefix'];
}
}
catch (e) {
}
return defaultLibraryPrefix;
}
function transform(options) {
const target = Object.assign({}, options);
const defaultSourceRoot = options.rootDir !== undefined ? options.rootDir : defaults_1.DEFAULT_LIB_PATH;
if (!target.name) {
throw new schematics_1.SchematicsException('Option (name) is required.');
}
target.language = !!target.language ? target.language : defaults_1.DEFAULT_LANGUAGE;
target.name = (0, formatting_1.normalizeToKebabOrSnakeCase)(target.name);
target.path =
target.path !== undefined
? (0, core_1.join)((0, core_1.normalize)(defaultSourceRoot), target.path)
: (0, core_1.normalize)(defaultSourceRoot);
target.prefix = target.prefix || getDefaultLibraryPrefix();
return target;
}
function updatePackageJson(options) {
return (host) => {
if (!host.exists('package.json')) {
return host;
}
const distRoot = (0, core_1.join)(options.path, options.name, 'src');
const packageKey = options.prefix
? options.prefix + '/' + options.name
: options.name;
return updateJsonFile(host, 'package.json', (packageJson) => {
updateNpmScripts(packageJson.scripts, options);
updateJestConfig(packageJson.jest, options, packageKey, distRoot);
});
};
}
function updateJestConfig(jestOptions, options, packageKey, distRoot) {
if (!jestOptions) {
return;
}
if (jestOptions.rootDir === defaults_1.DEFAULT_PATH_NAME) {
jestOptions.rootDir = '.';
jestOptions.coverageDirectory = './coverage';
}
const defaultSourceRoot = options.rootDir !== undefined ? options.rootDir : defaults_1.DEFAULT_LIB_PATH;
const jestSourceRoot = `<rootDir>/${defaultSourceRoot}/`;
if (!jestOptions.roots) {
jestOptions.roots = ['<rootDir>/src/', jestSourceRoot];
}
else if (jestOptions.roots.indexOf(jestSourceRoot) < 0) {
jestOptions.roots.push(jestSourceRoot);
}
if (!jestOptions.moduleNameMapper) {
jestOptions.moduleNameMapper = {};
}
const packageKeyRegex = '^' + packageKey + '(|/.*)$';
const packageRoot = (0, core_1.join)('<rootDir>', distRoot);
jestOptions.moduleNameMapper[packageKeyRegex] = (0, core_1.join)(packageRoot, '$1');
}
function updateNpmScripts(scripts, options) {
if (!scripts) {
return;
}
const defaultFormatScriptName = 'format';
if (!scripts[defaultFormatScriptName]) {
return;
}
if (scripts[defaultFormatScriptName] &&
scripts[defaultFormatScriptName].indexOf(defaults_1.DEFAULT_PATH_NAME) >= 0) {
const defaultSourceRoot = options.rootDir !== undefined ? options.rootDir : defaults_1.DEFAULT_LIB_PATH;
scripts[defaultFormatScriptName] = `prettier --write "src/**/*.ts" "test/**/*.ts" "${defaultSourceRoot}/**/*.ts"`;
}
}
function updateJestEndToEnd(options) {
return (host) => {
const pathToFile = (0, core_1.join)('test', 'jest-e2e.json');
if (!host.exists(pathToFile)) {
return host;
}
const distRoot = (0, core_1.join)(options.path, options.name, 'src');
const packageKey = options.prefix
? options.prefix + '/' + options.name
: options.name;
return updateJsonFile(host, pathToFile, (jestOptions) => {
if (!jestOptions.moduleNameMapper) {
jestOptions.moduleNameMapper = {};
}
const deepPackagePath = packageKey + '/(.*)';
const packageRoot = '<rootDir>/../' + distRoot;
jestOptions.moduleNameMapper[deepPackagePath] = packageRoot + '/$1';
jestOptions.moduleNameMapper[packageKey] = packageRoot;
});
};
}
function updateJsonFile(host, path, callback) {
const source = host.read(path);
if (source) {
const sourceText = source.toString('utf-8');
const json = (0, jsonc_parser_1.parse)(sourceText);
callback(json);
host.overwrite(path, JSON.stringify(json, null, 2));
}
return host;
}
function updateTsConfig(packageName, packagePrefix, root) {
return (host) => {
if (!host.exists('tsconfig.json')) {
return host;
}
const distRoot = (0, core_1.join)(root, packageName, 'src');
const packageKey = packagePrefix
? packagePrefix + '/' + packageName
: packageName;
return updateJsonFile(host, 'tsconfig.json', (tsconfig) => {
if (!tsconfig.compilerOptions) {
tsconfig.compilerOptions = {};
}
if (!tsconfig.compilerOptions.baseUrl) {
tsconfig.compilerOptions.baseUrl = './';
}
if (!tsconfig.compilerOptions.paths) {
tsconfig.compilerOptions.paths = {};
}
if (!tsconfig.compilerOptions.paths[packageKey]) {
tsconfig.compilerOptions.paths[packageKey] = [];
}
tsconfig.compilerOptions.paths[packageKey].push(distRoot);
const deepPackagePath = packageKey + '/*';
if (!tsconfig.compilerOptions.paths[deepPackagePath]) {
tsconfig.compilerOptions.paths[deepPackagePath] = [];
}
tsconfig.compilerOptions.paths[deepPackagePath].push(distRoot + '/*');
});
};
}
function addLibraryToCliOptions(projectRoot, projectName) {
const rootPath = (0, core_1.join)(projectRoot, projectName);
const project = {
type: defaults_1.PROJECT_TYPE.LIBRARY,
root: rootPath,
entryFile: 'index',
sourceRoot: (0, core_1.join)(rootPath, 'src'),
compilerOptions: {
tsConfigPath: (0, core_1.join)(rootPath, 'tsconfig.lib.json'),
},
};
return (host) => {
const nestFileExists = host.exists('nest.json');
let nestCliFileExists = host.exists('nest-cli.json');
if (!nestCliFileExists && !nestFileExists) {
host.create('nest-cli.json', '{}');
nestCliFileExists = true;
}
return updateJsonFile(host, nestCliFileExists ? 'nest-cli.json' : 'nest.json', (optionsFile) => {
if (!optionsFile.projects) {
optionsFile.projects = {};
}
if (!optionsFile.compilerOptions) {
optionsFile.compilerOptions = {};
}
if (optionsFile.compilerOptions.webpack === undefined) {
optionsFile.compilerOptions.webpack = true;
}
if (optionsFile.projects[projectName]) {
throw new schematics_1.SchematicsException(`Project "${projectName}" exists in this workspace already.`);
}
optionsFile.projects[projectName] = project;
});
};
}
function generate(options) {
const path = (0, core_1.join)(options.path, options.name);
return (0, schematics_1.apply)((0, schematics_1.url)((0, core_1.join)('./files', options.language)), [
(0, schematics_1.template)({
...core_1.strings,
...options,
}),
(0, schematics_1.move)(path),
]);
}

View File

@@ -0,0 +1,37 @@
{
"$schema": "http://json-schema.org/schema",
"$id": "SchematicsNestLibrary",
"title": "Nest Library Options Schema",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the library.",
"$default": {
"$source": "argv",
"index": 0
},
"x-prompt": "What name would you like to use for the library?"
},
"prefix": {
"type": "string",
"description": "The prefix of the library.",
"x-prompt": "What prefix would you like to use for the library (default: @app or 'defaultLibraryPrefix' setting value)?"
},
"language": {
"type": "string",
"description": "Nest library language."
},
"path": {
"type": "string",
"format": "path",
"description": "The path to create the library."
},
"rootDir": {
"type": "string",
"format": "path",
"description": "The libraries root directory."
}
},
"required": ["name", "prefix"]
}