Initialize Hot Desking app with web and API services
- Set up SvelteKit for the web interface with Tailwind CSS. - Build the API using NestJS with Prisma ORM for database interaction. - Add environment variable management and docker-compose for PostgreSQL and PgAdmin instances. - Create shared data models for consistent typing across services. - Establish basic routing and layouts for web and API services.main
commit
1faa0d5c8f
|
|
@ -0,0 +1,15 @@
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
|
||||||
|
/node_modules
|
||||||
|
**/node_modules
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
.vscode/*
|
||||||
|
.idea/*
|
||||||
|
**/.idea
|
||||||
|
**/.svelte-kit
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Ignored default folder with query files
|
||||||
|
/queries/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="AutoImportSettings">
|
||||||
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
|
</component>
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="6c8b3c54-eabb-40e5-967f-c7b594c750bc" name="Changes" comment="">
|
||||||
|
<change afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/.idea/.gitignore" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/prompts.md" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/index.ts" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/tsconfig.json" afterDir="false" />
|
||||||
|
</list>
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="EmbeddingIndexingInfo">
|
||||||
|
<option name="cachedIndexableFilesCount" value="10" />
|
||||||
|
<option name="fileBasedEmbeddingIndicesEnabled" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="McpProjectServerCommands">
|
||||||
|
<commands />
|
||||||
|
<urls />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectColorInfo">{
|
||||||
|
"associatedIndex": 0,
|
||||||
|
"fromUser": false
|
||||||
|
}</component>
|
||||||
|
<component name="ProjectId" id="3BXlUbAsiEmEvH0PacGIZgCuvpY" />
|
||||||
|
<component name="ProjectViewState">
|
||||||
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
|
<option name="showLibraryContents" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent"><![CDATA[{
|
||||||
|
"keyToString": {
|
||||||
|
"Docker.docker-compose.yml: Compose Deployment.executor": "Run",
|
||||||
|
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
||||||
|
"RunOnceActivity.MCP Project settings loaded": "true",
|
||||||
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
|
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||||
|
"RunOnceActivity.git.unshallow": "true",
|
||||||
|
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
||||||
|
"codeWithMe.voiceChat.enabledByDefault": "false",
|
||||||
|
"com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1": "true",
|
||||||
|
"git-widget-placeholder": "main",
|
||||||
|
"javascript.preferred.runtime.type.id": "node",
|
||||||
|
"junie.onboarding.icon.badge.shown": "true",
|
||||||
|
"node.js.detected.package.eslint": "true",
|
||||||
|
"node.js.detected.package.tslint": "true",
|
||||||
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
|
"nodejs_interpreter_path": "/home/micosil/.nvm/versions/node/v22.21.1/bin/node",
|
||||||
|
"nodejs_package_manager_path": "npm",
|
||||||
|
"npm.api > start:dev.executor": "Run",
|
||||||
|
"npm.web > dev.executor": "Run",
|
||||||
|
"settings.editor.selected.configurable": "settings.javascript.runtime",
|
||||||
|
"to.speed.mode.migration.done": "true",
|
||||||
|
"ts.external.directory.path": "/home/micosil/WebstormProjects/desker/node_modules/typescript/lib",
|
||||||
|
"vue.rearranger.settings.migration": "true"
|
||||||
|
}
|
||||||
|
}]]></component>
|
||||||
|
<component name="RunManager" selected="Docker.docker-compose.yml: Compose Deployment">
|
||||||
|
<configuration default="true" type="docker-deploy" factoryName="docker-compose.yml" temporary="true">
|
||||||
|
<deployment type="docker-compose.yml" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
<configuration name="docker-compose.yml: Compose Deployment" type="docker-deploy" factoryName="docker-compose.yml" temporary="true" server-name="Docker">
|
||||||
|
<deployment type="docker-compose.yml">
|
||||||
|
<settings>
|
||||||
|
<option name="sourceFilePath" value="docker-compose.yml" />
|
||||||
|
</settings>
|
||||||
|
</deployment>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
<configuration name="api > start:dev" type="js.build_tools.npm" temporary="true" nameIsGenerated="true">
|
||||||
|
<package-json value="$PROJECT_DIR$/apps/api/package.json" />
|
||||||
|
<command value="run" />
|
||||||
|
<scripts>
|
||||||
|
<script value="start:dev" />
|
||||||
|
</scripts>
|
||||||
|
<node-interpreter value="project" />
|
||||||
|
<envs />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
<configuration name="web > dev" type="js.build_tools.npm" temporary="true" nameIsGenerated="true">
|
||||||
|
<package-json value="$PROJECT_DIR$/apps/web/package.json" />
|
||||||
|
<command value="run" />
|
||||||
|
<scripts>
|
||||||
|
<script value="dev" />
|
||||||
|
</scripts>
|
||||||
|
<node-interpreter value="$USER_HOME$/.nvm/versions/node/v22.21.1/bin/node" />
|
||||||
|
<envs />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
<recent_temporary>
|
||||||
|
<list>
|
||||||
|
<item itemvalue="npm.api > start:dev" />
|
||||||
|
<item itemvalue="Docker.docker-compose.yml: Compose Deployment" />
|
||||||
|
<item itemvalue="npm.web > dev" />
|
||||||
|
</list>
|
||||||
|
</recent_temporary>
|
||||||
|
</component>
|
||||||
|
<component name="SharedIndexes">
|
||||||
|
<attachedChunks>
|
||||||
|
<set>
|
||||||
|
<option value="bundled-js-predefined-d6986cc7102b-3bd3a6803838-JavaScript-WS-261.22158.274" />
|
||||||
|
</set>
|
||||||
|
</attachedChunks>
|
||||||
|
</component>
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="6c8b3c54-eabb-40e5-967f-c7b594c750bc" name="Changes" comment="" />
|
||||||
|
<created>1774643312599</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1774643312599</updated>
|
||||||
|
<workItem from="1774643313611" duration="74000" />
|
||||||
|
<workItem from="1774643422240" duration="2753000" />
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
<option name="version" value="3" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
DATABASE_URL="postgresql://postgres:postgres@localhost:5433/hotdesking"
|
||||||
|
PORT=3000
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
<p align="center">
|
||||||
|
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
||||||
|
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
||||||
|
|
||||||
|
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
|
||||||
|
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
|
||||||
|
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
|
||||||
|
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||||
|
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||||
|
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
|
||||||
|
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
|
||||||
|
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
|
||||||
|
</p>
|
||||||
|
<!--[](https://opencollective.com/nest#backer)
|
||||||
|
[](https://opencollective.com/nest#sponsor)-->
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compile and run the project
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# development
|
||||||
|
$ npm run start
|
||||||
|
|
||||||
|
# watch mode
|
||||||
|
$ npm run start:dev
|
||||||
|
|
||||||
|
# production mode
|
||||||
|
$ npm run start:prod
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# unit tests
|
||||||
|
$ npm run test
|
||||||
|
|
||||||
|
# e2e tests
|
||||||
|
$ npm run test:e2e
|
||||||
|
|
||||||
|
# test coverage
|
||||||
|
$ npm run test:cov
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
|
||||||
|
|
||||||
|
If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install -g @nestjs/mau
|
||||||
|
$ mau deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
Check out a few resources that may come in handy when working with NestJS:
|
||||||
|
|
||||||
|
- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
|
||||||
|
- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
|
||||||
|
- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
|
||||||
|
- Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
|
||||||
|
- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
|
||||||
|
- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
|
||||||
|
- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
|
||||||
|
- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||||
|
|
||||||
|
## Stay in touch
|
||||||
|
|
||||||
|
- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
|
||||||
|
- Website - [https://nestjs.com](https://nestjs.com/)
|
||||||
|
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { AppService } from './app.service';
|
||||||
|
export declare class AppController {
|
||||||
|
private readonly appService;
|
||||||
|
constructor(appService: AppService);
|
||||||
|
getHello(): string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.AppController = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const app_service_1 = require("./app.service");
|
||||||
|
let AppController = class AppController {
|
||||||
|
appService;
|
||||||
|
constructor(appService) {
|
||||||
|
this.appService = appService;
|
||||||
|
}
|
||||||
|
getHello() {
|
||||||
|
return this.appService.getHello();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.AppController = AppController;
|
||||||
|
__decorate([
|
||||||
|
(0, common_1.Get)(),
|
||||||
|
__metadata("design:type", Function),
|
||||||
|
__metadata("design:paramtypes", []),
|
||||||
|
__metadata("design:returntype", String)
|
||||||
|
], AppController.prototype, "getHello", null);
|
||||||
|
exports.AppController = AppController = __decorate([
|
||||||
|
(0, common_1.Controller)(),
|
||||||
|
__metadata("design:paramtypes", [app_service_1.AppService])
|
||||||
|
], AppController);
|
||||||
|
//# sourceMappingURL=app.controller.js.map
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"app.controller.js","sourceRoot":"","sources":["../src/app.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAiD;AACjD,+CAA2C;AAGpC,IAAM,aAAa,GAAnB,MAAM,aAAa;IACK;IAA7B,YAA6B,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IAAG,CAAC;IAGvD,QAAQ;QACN,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC;CACF,CAAA;AAPY,sCAAa;AAIxB;IADC,IAAA,YAAG,GAAE;;;;6CAGL;wBANU,aAAa;IADzB,IAAA,mBAAU,GAAE;qCAE8B,wBAAU;GADxC,aAAa,CAOzB"}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export declare class AppModule {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.AppModule = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const app_controller_1 = require("./app.controller");
|
||||||
|
const app_service_1 = require("./app.service");
|
||||||
|
const prisma_module_1 = require("./prisma/prisma.module");
|
||||||
|
const spaces_module_1 = require("./spaces/spaces.module");
|
||||||
|
let AppModule = class AppModule {
|
||||||
|
};
|
||||||
|
exports.AppModule = AppModule;
|
||||||
|
exports.AppModule = AppModule = __decorate([
|
||||||
|
(0, common_1.Module)({
|
||||||
|
imports: [prisma_module_1.PrismaModule, spaces_module_1.SpacesModule],
|
||||||
|
controllers: [app_controller_1.AppController],
|
||||||
|
providers: [app_service_1.AppService],
|
||||||
|
})
|
||||||
|
], AppModule);
|
||||||
|
//# sourceMappingURL=app.module.js.map
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,qDAAiD;AACjD,+CAA2C;AAC3C,0DAAsD;AACtD,0DAAsD;AAO/C,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IALrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,EAAE,4BAAY,CAAC;QACrC,WAAW,EAAE,CAAC,8BAAa,CAAC;QAC5B,SAAS,EAAE,CAAC,wBAAU,CAAC;KACxB,CAAC;GACW,SAAS,CAAG"}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
export declare class AppService {
|
||||||
|
getHello(): string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.AppService = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
let AppService = class AppService {
|
||||||
|
getHello() {
|
||||||
|
return 'Hello World!';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.AppService = AppService;
|
||||||
|
exports.AppService = AppService = __decorate([
|
||||||
|
(0, common_1.Injectable)()
|
||||||
|
], AppService);
|
||||||
|
//# sourceMappingURL=app.service.js.map
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"app.service.js","sourceRoot":"","sources":["../src/app.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAGrC,IAAM,UAAU,GAAhB,MAAM,UAAU;IACrB,QAAQ;QACN,OAAO,cAAc,CAAC;IACxB,CAAC;CACF,CAAA;AAJY,gCAAU;qBAAV,UAAU;IADtB,IAAA,mBAAU,GAAE;GACA,UAAU,CAItB"}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
import { ArgumentsHost, ExceptionFilter } from '@nestjs/common';
|
||||||
|
export declare class HttpExceptionFilter implements ExceptionFilter {
|
||||||
|
catch(exception: unknown, host: ArgumentsHost): void;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.HttpExceptionFilter = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
let HttpExceptionFilter = class HttpExceptionFilter {
|
||||||
|
catch(exception, host) {
|
||||||
|
const ctx = host.switchToHttp();
|
||||||
|
const response = ctx.getResponse();
|
||||||
|
const request = ctx.getRequest();
|
||||||
|
const isHttpException = exception instanceof common_1.HttpException;
|
||||||
|
const status = isHttpException
|
||||||
|
? exception.getStatus()
|
||||||
|
: common_1.HttpStatus.INTERNAL_SERVER_ERROR;
|
||||||
|
const message = isHttpException
|
||||||
|
? exception.getResponse()
|
||||||
|
: 'Internal server error';
|
||||||
|
response.status(status).json({
|
||||||
|
statusCode: status,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
path: request.url,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.HttpExceptionFilter = HttpExceptionFilter;
|
||||||
|
exports.HttpExceptionFilter = HttpExceptionFilter = __decorate([
|
||||||
|
(0, common_1.Catch)()
|
||||||
|
], HttpExceptionFilter);
|
||||||
|
//# sourceMappingURL=http-exception.filter.js.map
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"http-exception.filter.js","sourceRoot":"","sources":["../../../src/common/filters/http-exception.filter.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAMwB;AAIjB,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAC9B,KAAK,CAAC,SAAkB,EAAE,IAAmB;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAY,CAAC;QAC7C,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAW,CAAC;QAE1C,MAAM,eAAe,GAAG,SAAS,YAAY,sBAAa,CAAC;QAE3D,MAAM,MAAM,GAAG,eAAe;YAC5B,CAAC,CAAC,SAAS,CAAC,SAAS,EAAE;YACvB,CAAC,CAAC,mBAAU,CAAC,qBAAqB,CAAC;QAErC,MAAM,OAAO,GAAG,eAAe;YAC7B,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE;YACzB,CAAC,CAAC,uBAAuB,CAAC;QAE5B,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;YAC3B,UAAU,EAAE,MAAM;YAClB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,IAAI,EAAE,OAAO,CAAC,GAAG;YACjB,OAAO;SACR,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAvBY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,cAAK,GAAE;GACK,mBAAmB,CAuB/B"}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export {};
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const core_1 = require("@nestjs/core");
|
||||||
|
const app_module_1 = require("./app.module");
|
||||||
|
const http_exception_filter_1 = require("./common/filters/http-exception.filter");
|
||||||
|
async function bootstrap() {
|
||||||
|
const app = await core_1.NestFactory.create(app_module_1.AppModule);
|
||||||
|
app.useGlobalPipes(new common_1.ValidationPipe({
|
||||||
|
whitelist: true,
|
||||||
|
transform: true,
|
||||||
|
forbidNonWhitelisted: true,
|
||||||
|
}));
|
||||||
|
app.useGlobalFilters(new http_exception_filter_1.HttpExceptionFilter());
|
||||||
|
app.enableCors({
|
||||||
|
origin: ['http://localhost:5173'],
|
||||||
|
credentials: true,
|
||||||
|
});
|
||||||
|
await app.listen(process.env.PORT ?? 3000);
|
||||||
|
}
|
||||||
|
bootstrap();
|
||||||
|
//# sourceMappingURL=main.js.map
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;AAAA,2CAAgD;AAChD,uCAA2C;AAC3C,6CAAyC;AACzC,kFAA6E;AAE7E,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,CAAC;IAEhD,GAAG,CAAC,cAAc,CAChB,IAAI,uBAAc,CAAC;QACjB,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,IAAI;QACf,oBAAoB,EAAE,IAAI;KAC3B,CAAC,CACH,CAAC;IAEF,GAAG,CAAC,gBAAgB,CAAC,IAAI,2CAAmB,EAAE,CAAC,CAAC;IAEhD,GAAG,CAAC,UAAU,CAAC;QACb,MAAM,EAAE,CAAC,uBAAuB,CAAC;QACjC,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;IAEH,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC7C,CAAC;AACD,SAAS,EAAE,CAAC"}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export declare class PrismaModule {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.PrismaModule = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const prisma_service_1 = require("./prisma.service");
|
||||||
|
let PrismaModule = class PrismaModule {
|
||||||
|
};
|
||||||
|
exports.PrismaModule = PrismaModule;
|
||||||
|
exports.PrismaModule = PrismaModule = __decorate([
|
||||||
|
(0, common_1.Global)(),
|
||||||
|
(0, common_1.Module)({
|
||||||
|
providers: [prisma_service_1.PrismaService],
|
||||||
|
exports: [prisma_service_1.PrismaService],
|
||||||
|
})
|
||||||
|
], PrismaModule);
|
||||||
|
//# sourceMappingURL=prisma.module.js.map
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"prisma.module.js","sourceRoot":"","sources":["../../src/prisma/prisma.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAgD;AAChD,qDAAiD;AAO1C,IAAM,YAAY,GAAlB,MAAM,YAAY;CAAG,CAAA;AAAf,oCAAY;uBAAZ,YAAY;IALxB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,8BAAa,CAAC;QAC1B,OAAO,EAAE,CAAC,8BAAa,CAAC;KACzB,CAAC;GACW,YAAY,CAAG"}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
export declare class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
||||||
|
onModuleInit(): Promise<void>;
|
||||||
|
onModuleDestroy(): Promise<void>;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.PrismaService = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const client_1 = require("@prisma/client");
|
||||||
|
let PrismaService = class PrismaService extends client_1.PrismaClient {
|
||||||
|
async onModuleInit() {
|
||||||
|
await this.$connect();
|
||||||
|
}
|
||||||
|
async onModuleDestroy() {
|
||||||
|
await this.$disconnect();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.PrismaService = PrismaService;
|
||||||
|
exports.PrismaService = PrismaService = __decorate([
|
||||||
|
(0, common_1.Injectable)()
|
||||||
|
], PrismaService);
|
||||||
|
//# sourceMappingURL=prisma.service.js.map
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"prisma.service.js","sourceRoot":"","sources":["../../src/prisma/prisma.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA2E;AAC3E,2CAA8C;AAGvC,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,qBAAY;IAC7C,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;IAC3B,CAAC;CACF,CAAA;AARY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;GACA,aAAa,CAQzB"}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { SpacesService } from './spaces.service';
|
||||||
|
export declare class SpacesController {
|
||||||
|
private readonly spacesService;
|
||||||
|
constructor(spacesService: SpacesService);
|
||||||
|
findAll(): import("@hot-desking/shared").SpaceDTO[];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.SpacesController = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const spaces_service_1 = require("./spaces.service");
|
||||||
|
let SpacesController = class SpacesController {
|
||||||
|
spacesService;
|
||||||
|
constructor(spacesService) {
|
||||||
|
this.spacesService = spacesService;
|
||||||
|
}
|
||||||
|
findAll() {
|
||||||
|
return this.spacesService.findAll();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.SpacesController = SpacesController;
|
||||||
|
__decorate([
|
||||||
|
(0, common_1.Get)(),
|
||||||
|
__metadata("design:type", Function),
|
||||||
|
__metadata("design:paramtypes", []),
|
||||||
|
__metadata("design:returntype", void 0)
|
||||||
|
], SpacesController.prototype, "findAll", null);
|
||||||
|
exports.SpacesController = SpacesController = __decorate([
|
||||||
|
(0, common_1.Controller)('spaces'),
|
||||||
|
__metadata("design:paramtypes", [spaces_service_1.SpacesService])
|
||||||
|
], SpacesController);
|
||||||
|
//# sourceMappingURL=spaces.controller.js.map
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"spaces.controller.js","sourceRoot":"","sources":["../../src/spaces/spaces.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAiD;AACjD,qDAAiD;AAG1C,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IACE;IAA7B,YAA6B,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;IAAG,CAAC;IAG7D,OAAO;QACL,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;IACtC,CAAC;CACF,CAAA;AAPY,4CAAgB;AAI3B;IADC,IAAA,YAAG,GAAE;;;;+CAGL;2BANU,gBAAgB;IAD5B,IAAA,mBAAU,EAAC,QAAQ,CAAC;qCAEyB,8BAAa;GAD9C,gBAAgB,CAO5B"}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
export declare class SpacesModule {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.SpacesModule = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const spaces_controller_1 = require("./spaces.controller");
|
||||||
|
const spaces_service_1 = require("./spaces.service");
|
||||||
|
let SpacesModule = class SpacesModule {
|
||||||
|
};
|
||||||
|
exports.SpacesModule = SpacesModule;
|
||||||
|
exports.SpacesModule = SpacesModule = __decorate([
|
||||||
|
(0, common_1.Module)({
|
||||||
|
controllers: [spaces_controller_1.SpacesController],
|
||||||
|
providers: [spaces_service_1.SpacesService],
|
||||||
|
})
|
||||||
|
], SpacesModule);
|
||||||
|
//# sourceMappingURL=spaces.module.js.map
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"spaces.module.js","sourceRoot":"","sources":["../../src/spaces/spaces.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2DAAuD;AACvD,qDAAiD;AAM1C,IAAM,YAAY,GAAlB,MAAM,YAAY;CAAG,CAAA;AAAf,oCAAY;uBAAZ,YAAY;IAJxB,IAAA,eAAM,EAAC;QACN,WAAW,EAAE,CAAC,oCAAgB,CAAC;QAC/B,SAAS,EAAE,CAAC,8BAAa,CAAC;KAC3B,CAAC;GACW,YAAY,CAAG"}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
import { SpaceDTO } from '@hot-desking/shared';
|
||||||
|
export declare class SpacesService {
|
||||||
|
findAll(): SpaceDTO[];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
"use strict";
|
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.SpacesService = void 0;
|
||||||
|
const common_1 = require("@nestjs/common");
|
||||||
|
const shared_1 = require("@hot-desking/shared");
|
||||||
|
let SpacesService = class SpacesService {
|
||||||
|
findAll() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
name: 'Desk 1',
|
||||||
|
type: shared_1.SpaceType.Desk,
|
||||||
|
x: 10,
|
||||||
|
y: 20,
|
||||||
|
status: shared_1.BookingStatus.Available,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.SpacesService = SpacesService;
|
||||||
|
exports.SpacesService = SpacesService = __decorate([
|
||||||
|
(0, common_1.Injectable)()
|
||||||
|
], SpacesService);
|
||||||
|
//# sourceMappingURL=spaces.service.js.map
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"spaces.service.js","sourceRoot":"","sources":["../../src/spaces/spaces.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAC5C,gDAAyE;AAGlE,IAAM,aAAa,GAAnB,MAAM,aAAa;IACxB,OAAO;QACL,OAAO;YACL;gBACE,EAAE,EAAE,GAAG;gBACP,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,kBAAS,CAAC,IAAI;gBACpB,CAAC,EAAE,EAAE;gBACL,CAAC,EAAE,EAAE;gBACL,MAAM,EAAE,sBAAa,CAAC,SAAS;aAChC;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAbY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;GACA,aAAa,CAazB"}
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,35 @@
|
||||||
|
// @ts-check
|
||||||
|
import eslint from '@eslint/js';
|
||||||
|
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
||||||
|
import globals from 'globals';
|
||||||
|
import tseslint from 'typescript-eslint';
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
{
|
||||||
|
ignores: ['eslint.config.mjs'],
|
||||||
|
},
|
||||||
|
eslint.configs.recommended,
|
||||||
|
...tseslint.configs.recommendedTypeChecked,
|
||||||
|
eslintPluginPrettierRecommended,
|
||||||
|
{
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
...globals.node,
|
||||||
|
...globals.jest,
|
||||||
|
},
|
||||||
|
sourceType: 'commonjs',
|
||||||
|
parserOptions: {
|
||||||
|
projectService: true,
|
||||||
|
tsconfigRootDir: import.meta.dirname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-floating-promises': 'warn',
|
||||||
|
'@typescript-eslint/no-unsafe-argument': 'warn',
|
||||||
|
"prettier/prettier": ["error", { endOfLine: "auto" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/nest-cli",
|
||||||
|
"collection": "@nestjs/schematics",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"compilerOptions": {
|
||||||
|
"deleteOutDir": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
{
|
||||||
|
"name": "api",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "",
|
||||||
|
"author": "",
|
||||||
|
"private": true,
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"scripts": {
|
||||||
|
"build": "nest build",
|
||||||
|
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||||
|
"start": "nest start",
|
||||||
|
"start:dev": "nest start --watch",
|
||||||
|
"start:debug": "nest start --debug --watch",
|
||||||
|
"start:prod": "node dist/main",
|
||||||
|
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||||
|
"test": "jest",
|
||||||
|
"test:watch": "jest --watch",
|
||||||
|
"test:cov": "jest --coverage",
|
||||||
|
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||||
|
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nestjs/common": "^10.4.22",
|
||||||
|
"@nestjs/core": "^10.4.22",
|
||||||
|
"@nestjs/platform-express": "^10.4.22",
|
||||||
|
"@prisma/client": "^6.4.0",
|
||||||
|
"class-transformer": "^0.5.1",
|
||||||
|
"class-validator": "^0.15.1",
|
||||||
|
"prisma": "^6.4.0",
|
||||||
|
"reflect-metadata": "^0.2.2",
|
||||||
|
"rxjs": "^7.8.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/eslintrc": "^3.2.0",
|
||||||
|
"@eslint/js": "^9.18.0",
|
||||||
|
"@nestjs/cli": "^10.4.9",
|
||||||
|
"@nestjs/schematics": "^10.2.3",
|
||||||
|
"@nestjs/testing": "^10.4.22",
|
||||||
|
"@types/express": "^5.0.6",
|
||||||
|
"@types/jest": "^30.0.0",
|
||||||
|
"@types/node": "^22.19.15",
|
||||||
|
"@types/supertest": "^6.0.2",
|
||||||
|
"eslint": "^9.18.0",
|
||||||
|
"eslint-config-prettier": "^10.0.1",
|
||||||
|
"eslint-plugin-prettier": "^5.2.2",
|
||||||
|
"globals": "^16.0.0",
|
||||||
|
"jest": "^30.3.0",
|
||||||
|
"prettier": "^3.4.2",
|
||||||
|
"source-map-support": "^0.5.21",
|
||||||
|
"supertest": "^7.0.0",
|
||||||
|
"ts-jest": "^29.4.6",
|
||||||
|
"ts-loader": "^9.5.4",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"tsconfig-paths": "^4.2.0",
|
||||||
|
"typescript": "^5.9.3",
|
||||||
|
"typescript-eslint": "^8.20.0"
|
||||||
|
},
|
||||||
|
"jest": {
|
||||||
|
"moduleFileExtensions": [
|
||||||
|
"js",
|
||||||
|
"json",
|
||||||
|
"ts"
|
||||||
|
],
|
||||||
|
"rootDir": "src",
|
||||||
|
"testRegex": ".*\\.spec\\.ts$",
|
||||||
|
"transform": {
|
||||||
|
"^.+\\.(t|j)s$": "ts-jest"
|
||||||
|
},
|
||||||
|
"collectCoverageFrom": [
|
||||||
|
"**/*.(t|j)s"
|
||||||
|
],
|
||||||
|
"coverageDirectory": "../coverage",
|
||||||
|
"testEnvironment": "node"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
// apps/api/prisma/schema.prisma
|
||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "postgresql"
|
||||||
|
url = env("DATABASE_URL")
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { AppController } from './app.controller';
|
||||||
|
import { AppService } from './app.service';
|
||||||
|
|
||||||
|
describe('AppController', () => {
|
||||||
|
let appController: AppController;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const app: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [AppController],
|
||||||
|
providers: [AppService],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
appController = app.get<AppController>(AppController);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('root', () => {
|
||||||
|
it('should return "Hello World!"', () => {
|
||||||
|
expect(appController.getHello()).toBe('Hello World!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Controller, Get } from '@nestjs/common';
|
||||||
|
import { AppService } from './app.service';
|
||||||
|
|
||||||
|
@Controller()
|
||||||
|
export class AppController {
|
||||||
|
constructor(private readonly appService: AppService) {}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
getHello(): string {
|
||||||
|
return this.appService.getHello();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { AppController } from './app.controller';
|
||||||
|
import { AppService } from './app.service';
|
||||||
|
import { PrismaModule } from './prisma/prisma.module';
|
||||||
|
import { SpacesModule } from './spaces/spaces.module';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [PrismaModule, SpacesModule],
|
||||||
|
controllers: [AppController],
|
||||||
|
providers: [AppService],
|
||||||
|
})
|
||||||
|
export class AppModule {}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AppService {
|
||||||
|
getHello(): string {
|
||||||
|
return 'Hello World!';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
import {
|
||||||
|
ArgumentsHost,
|
||||||
|
Catch,
|
||||||
|
ExceptionFilter,
|
||||||
|
HttpException,
|
||||||
|
HttpStatus,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { Request, Response } from 'express';
|
||||||
|
|
||||||
|
@Catch()
|
||||||
|
export class HttpExceptionFilter implements ExceptionFilter {
|
||||||
|
catch(exception: unknown, host: ArgumentsHost) {
|
||||||
|
const ctx = host.switchToHttp();
|
||||||
|
const response = ctx.getResponse<Response>();
|
||||||
|
const request = ctx.getRequest<Request>();
|
||||||
|
|
||||||
|
const isHttpException = exception instanceof HttpException;
|
||||||
|
|
||||||
|
const status = isHttpException
|
||||||
|
? exception.getStatus()
|
||||||
|
: HttpStatus.INTERNAL_SERVER_ERROR;
|
||||||
|
|
||||||
|
const message = isHttpException
|
||||||
|
? exception.getResponse()
|
||||||
|
: 'Internal server error';
|
||||||
|
|
||||||
|
response.status(status).json({
|
||||||
|
statusCode: status,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
path: request.url,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { ValidationPipe } from '@nestjs/common';
|
||||||
|
import { NestFactory } from '@nestjs/core';
|
||||||
|
import { AppModule } from './app.module';
|
||||||
|
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
|
||||||
|
|
||||||
|
async function bootstrap() {
|
||||||
|
const app = await NestFactory.create(AppModule);
|
||||||
|
|
||||||
|
app.useGlobalPipes(
|
||||||
|
new ValidationPipe({
|
||||||
|
whitelist: true,
|
||||||
|
transform: true,
|
||||||
|
forbidNonWhitelisted: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
app.useGlobalFilters(new HttpExceptionFilter());
|
||||||
|
|
||||||
|
app.enableCors({
|
||||||
|
origin: ['http://localhost:5173'],
|
||||||
|
credentials: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await app.listen(process.env.PORT ?? 3000);
|
||||||
|
}
|
||||||
|
bootstrap();
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Global, Module } from '@nestjs/common';
|
||||||
|
import { PrismaService } from './prisma.service';
|
||||||
|
|
||||||
|
@Global()
|
||||||
|
@Module({
|
||||||
|
providers: [PrismaService],
|
||||||
|
exports: [PrismaService],
|
||||||
|
})
|
||||||
|
export class PrismaModule {}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
||||||
|
async onModuleInit() {
|
||||||
|
await this.$connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
async onModuleDestroy() {
|
||||||
|
await this.$disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Controller, Get } from '@nestjs/common';
|
||||||
|
import { SpacesService } from './spaces.service';
|
||||||
|
|
||||||
|
@Controller('spaces')
|
||||||
|
export class SpacesController {
|
||||||
|
constructor(private readonly spacesService: SpacesService) {}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
findAll() {
|
||||||
|
return this.spacesService.findAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { SpacesController } from './spaces.controller';
|
||||||
|
import { SpacesService } from './spaces.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [SpacesController],
|
||||||
|
providers: [SpacesService],
|
||||||
|
})
|
||||||
|
export class SpacesModule {}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { SpaceDTO, SpaceType, BookingStatus } from '@hot-desking/shared';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class SpacesService {
|
||||||
|
findAll(): SpaceDTO[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
name: 'Desk 1',
|
||||||
|
type: SpaceType.Desk,
|
||||||
|
x: 10,
|
||||||
|
y: 20,
|
||||||
|
status: BookingStatus.Available,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { INestApplication } from '@nestjs/common';
|
||||||
|
import request from 'supertest';
|
||||||
|
import { App } from 'supertest/types';
|
||||||
|
import { AppModule } from './../src/app.module';
|
||||||
|
|
||||||
|
describe('AppController (e2e)', () => {
|
||||||
|
let app: INestApplication<App>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const moduleFixture: TestingModule = await Test.createTestingModule({
|
||||||
|
imports: [AppModule],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
app = moduleFixture.createNestApplication();
|
||||||
|
await app.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/ (GET)', () => {
|
||||||
|
return request(app.getHttpServer())
|
||||||
|
.get('/')
|
||||||
|
.expect(200)
|
||||||
|
.expect('Hello World!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"moduleFileExtensions": ["js", "json", "ts"],
|
||||||
|
"rootDir": ".",
|
||||||
|
"testEnvironment": "node",
|
||||||
|
"testRegex": ".e2e-spec.ts$",
|
||||||
|
"transform": {
|
||||||
|
"^.+\\.(t|j)s$": "ts-jest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"resolvePackageJsonExports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"declaration": true,
|
||||||
|
"removeComments": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"target": "ES2023",
|
||||||
|
"sourceMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"incremental": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"strictBindCallApply": false,
|
||||||
|
"noFallthroughCasesInSwitch": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
VITE_API_BASE_URL="http://localhost:3000"
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite dev",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@sveltejs/adapter-auto": "^3.3.1",
|
||||||
|
"@sveltejs/kit": "^2.0.0",
|
||||||
|
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
||||||
|
"autoprefixer": "^10.4.0",
|
||||||
|
"lucide-svelte": "^0.300.0",
|
||||||
|
"postcss": "^8.4.0",
|
||||||
|
"svelte": "^5.0.0",
|
||||||
|
"svelte-check": "^3.6.0",
|
||||||
|
"tailwindcss": "^3.4.0",
|
||||||
|
"tslib": "^2.4.1",
|
||||||
|
"typescript": "^5.0.0",
|
||||||
|
"vite": "^5.0.0"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"import-meta-resolve": "^4.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
%sveltekit.head%
|
||||||
|
</head>
|
||||||
|
<body data-sveltekit-preload-data="hover">
|
||||||
|
<div style="display: contents">%sveltekit.body%</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:3000';
|
||||||
|
|
||||||
|
export async function apiFetch<T>(
|
||||||
|
path: string,
|
||||||
|
options: RequestInit = {},
|
||||||
|
): Promise<T> {
|
||||||
|
const res = await fetch(`${API_BASE_URL}${path}`, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(options.headers ?? {}),
|
||||||
|
},
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const text = await res.text();
|
||||||
|
throw new Error(text || `Request failed: ${res.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json() as Promise<T>;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
<script>
|
||||||
|
import "../app.css";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="min-h-screen bg-gray-50">
|
||||||
|
<nav class="bg-white shadow-sm px-4 py-3 flex justify-between items-center">
|
||||||
|
<h1 class="text-xl font-bold text-indigo-600">Hot Desking</h1>
|
||||||
|
<div class="space-x-4">
|
||||||
|
<a href="/" class="text-gray-600 hover:text-indigo-600">Dashboard</a>
|
||||||
|
<a href="/login" class="text-gray-600 hover:text-indigo-600">Login</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main class="max-w-7xl mx-auto p-6">
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { apiFetch } from '$lib/api/client';
|
||||||
|
import type { SpaceDTO } from '@shared/index';
|
||||||
|
import { MapPin, Monitor as DeskIcon } from 'lucide-svelte';
|
||||||
|
|
||||||
|
let spaces: SpaceDTO[] = [];
|
||||||
|
let error: string | null = null;
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
try {
|
||||||
|
spaces = await apiFetch<SpaceDTO[]>('/spaces');
|
||||||
|
} catch (e: any) {
|
||||||
|
error = e.message;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<h2 class="text-2xl font-bold text-gray-800">Space Dashboard</h2>
|
||||||
|
<div class="flex items-center space-x-2 text-sm text-gray-500">
|
||||||
|
<MapPin size={16} />
|
||||||
|
<span>Main Office</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if error}
|
||||||
|
<div class="bg-red-50 border-l-4 border-red-400 p-4 text-red-700">
|
||||||
|
<p>Error loading spaces: {error}</p>
|
||||||
|
</div>
|
||||||
|
{:else if spaces.length === 0}
|
||||||
|
<p class="text-gray-500 italic">No spaces found or loading...</p>
|
||||||
|
{:else}
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
{#each spaces as space}
|
||||||
|
<div class="bg-white p-4 rounded-lg shadow border border-gray-100 flex items-center space-x-4">
|
||||||
|
<div class="p-3 bg-indigo-50 text-indigo-600 rounded-full">
|
||||||
|
<DeskIcon size={24} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-semibold text-gray-900">{space.name}</h3>
|
||||||
|
<p class="text-sm text-gray-500 capitalize">{space.type} • {space.status}</p>
|
||||||
|
</div>
|
||||||
|
<div class="ml-auto">
|
||||||
|
<span class="px-2 py-1 text-xs font-medium rounded-full
|
||||||
|
{space.status === 'Available' ? 'bg-green-100 text-green-700' : 'bg-orange-100 text-orange-700'}">
|
||||||
|
{space.status}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { LogIn } from 'lucide-svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="max-w-md mx-auto mt-20 bg-white p-8 rounded-xl shadow-lg border border-gray-100">
|
||||||
|
<div class="flex flex-col items-center mb-8">
|
||||||
|
<div class="p-4 bg-indigo-100 text-indigo-600 rounded-full mb-4">
|
||||||
|
<LogIn size={32} />
|
||||||
|
</div>
|
||||||
|
<h2 class="text-3xl font-bold text-gray-900">Sign In</h2>
|
||||||
|
<p class="text-gray-500">Access the Hot Desking system</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label for="email" class="block text-sm font-medium text-gray-700">Email Address</label>
|
||||||
|
<input type="email" id="email" class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500" placeholder="you@company.com" required>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="password" class="block text-sm font-medium text-gray-700">Password</label>
|
||||||
|
<input type="password" id="password" class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition-colors">
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import adapter from '@sveltejs/adapter-auto';
|
||||||
|
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||||
|
|
||||||
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
|
const config = {
|
||||||
|
preprocess: vitePreprocess(),
|
||||||
|
|
||||||
|
kit: {
|
||||||
|
adapter: adapter(),
|
||||||
|
alias: {
|
||||||
|
'@shared': '../../shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export default {
|
||||||
|
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"extends": "./.svelte-kit/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"strict": true,
|
||||||
|
"moduleResolution": "bundler"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [sveltekit()],
|
||||||
|
server: {
|
||||||
|
fs: {
|
||||||
|
allow: ['../../shared']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:16
|
||||||
|
container_name: hotdesking_postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
POSTGRES_DB: hotdesking
|
||||||
|
ports:
|
||||||
|
- "5433:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
pgadmin:
|
||||||
|
image: dpage/pgadmin4:8
|
||||||
|
container_name: hotdesking_pgadmin
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
PGADMIN_DEFAULT_EMAIL: admin@local.dev
|
||||||
|
PGADMIN_DEFAULT_PASSWORD: admin
|
||||||
|
ports:
|
||||||
|
- "5051:80"
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"name": "hot-desking-app",
|
||||||
|
"private": true,
|
||||||
|
"workspaces": [
|
||||||
|
"apps/*",
|
||||||
|
"shared"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"dev:web": "npm --workspace apps/web run dev",
|
||||||
|
"dev:api": "npm --workspace apps/api run start:dev",
|
||||||
|
"build": "npm run build --workspaces",
|
||||||
|
"lint": "npm run lint --workspaces"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
Stage 1: The Core Foundation (Structure & Auth)
|
||||||
|
|
||||||
|
Goal: Define the database and the hierarchical API.
|
||||||
|
|
||||||
|
Agent Prompt:
|
||||||
|
"Act as a Senior Backend Architect. Design a NestJS API and a PostgreSQL schema using Prisma/TypeORM.
|
||||||
|
|
||||||
|
Create a hierarchical data model: Organization -> Building -> Floor -> Space (where Space is an enum: Desk, Meeting Room, Amenity).
|
||||||
|
|
||||||
|
Implement RBAC (Role-Based Access Control) for roles: Admin, Supervisor, and Employee.
|
||||||
|
|
||||||
|
Provide the NestJS boilerplate for the Spaces module, including a recursive GET endpoint to fetch a full Floor layout.
|
||||||
|
|
||||||
|
Generate a SvelteKit login page and a basic dashboard that lists Buildings and Floors based on the user's Org."
|
||||||
|
|
||||||
|
Stage 2: Live State & Real-Time Booking
|
||||||
|
|
||||||
|
Goal: Implement WebSockets for instant UI updates.
|
||||||
|
|
||||||
|
Agent Prompt:
|
||||||
|
"Act as a Full-Stack Engineer. I need to implement real-time desk availability.
|
||||||
|
|
||||||
|
In the NestJS backend, set up a Socket.io Gateway. When a Reservation is created or cancelled, emit a space_status_changed event to a room identified by floorId.
|
||||||
|
|
||||||
|
Create the Reservations table in Postgres with fields for startTime, endTime, userId, and spaceId.
|
||||||
|
|
||||||
|
On the SvelteKit frontend, create a SpaceCard component that listens to the WebSocket. If a message arrives for its spaceId, it should immediately toggle its visual state (Available/Occupied) without a page reload."
|
||||||
|
|
||||||
|
Stage 3: The Visual Floorplan (Drag & Drop)
|
||||||
|
|
||||||
|
Goal: Create the interactive map editor.
|
||||||
|
|
||||||
|
Agent Prompt:
|
||||||
|
"Act as a Frontend Expert. I need a SvelteKit interface for an 'Admin Floorplan Editor.'
|
||||||
|
|
||||||
|
Create a component where an Admin can upload an image (JPG/PNG) of a floorplan to use as a background.
|
||||||
|
|
||||||
|
Implement a 'Toolbox' of Draggable icons (Desk, Toilet, Coffee, Meeting Room).
|
||||||
|
|
||||||
|
Use a library like svelte-dnd-action or interact.js to allow placing these icons on the floorplan.
|
||||||
|
|
||||||
|
On 'Save,' the component must calculate the percentage-based X,Y coordinates (to ensure responsiveness) and send an array of objects to the NestJS /spaces/batch-update endpoint."
|
||||||
|
|
||||||
|
Stage 4: Google Calendar Sync
|
||||||
|
|
||||||
|
Goal: Connect the booking system to the outside world.
|
||||||
|
|
||||||
|
Agent Prompt:
|
||||||
|
"Act as an Integration Specialist. I need to sync Meeting Room bookings with Google Calendar in NestJS.
|
||||||
|
|
||||||
|
Provide a service that uses googleapis to authenticate via a Service Account.
|
||||||
|
|
||||||
|
Write a 'Sync Service' that:
|
||||||
|
|
||||||
|
When a user books in-app, creates a GCal event.
|
||||||
|
|
||||||
|
Uses a Cron job to poll GCal every 5 minutes for external bookings and updates the local Reservations table.
|
||||||
|
|
||||||
|
Ensure that if a Google Event is deleted, the app marks the room as 'Available' locally."
|
||||||
|
|
||||||
|
Stage 5: Kiosk Mode (Tablet UI)
|
||||||
|
|
||||||
|
Goal: Build the high-visibility, simplified interface.
|
||||||
|
|
||||||
|
Agent Prompt:
|
||||||
|
"Act as a UI/UX Designer and Svelte Developer. Design a 'Kiosk Mode' page.
|
||||||
|
|
||||||
|
Route: /kiosk/:spaceId. This page should be 'Full Screen' and optimized for a 10-inch tablet.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
Large status indicator (Big Red/Green background).
|
||||||
|
|
||||||
|
Display 'Current Meeting' and 'Next Meeting' (fetched from the Google Sync service).
|
||||||
|
|
||||||
|
A 'Quick Book' button that allows a user to claim the room for 15, 30, or 60 minutes instantly.
|
||||||
|
|
||||||
|
Implement a simple PIN-code overlay if the user tries to exit the kiosk view to the main dashboard."
|
||||||
|
|
||||||
|
Suggested Next Step
|
||||||
|
|
||||||
|
Since Stage 1 is the bedrock, would you like me to generate the actual Prisma Schema or TypeORM Entities for that Org > Building > Floor > Desk hierarchy right now?
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
export declare enum SpaceType {
|
||||||
|
Desk = "Desk",
|
||||||
|
Room = "Room",
|
||||||
|
Amenity = "Amenity"
|
||||||
|
}
|
||||||
|
export declare enum BookingStatus {
|
||||||
|
Available = "Available",
|
||||||
|
Occupied = "Occupied",
|
||||||
|
Reserved = "Reserved",
|
||||||
|
OutOfService = "OutOfService"
|
||||||
|
}
|
||||||
|
export declare enum UserRole {
|
||||||
|
Admin = "Admin",
|
||||||
|
Supervisor = "Supervisor",
|
||||||
|
Employee = "Employee"
|
||||||
|
}
|
||||||
|
export interface SpaceDTO {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
type: SpaceType;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
status: BookingStatus;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.UserRole = exports.BookingStatus = exports.SpaceType = void 0;
|
||||||
|
var SpaceType;
|
||||||
|
(function (SpaceType) {
|
||||||
|
SpaceType["Desk"] = "Desk";
|
||||||
|
SpaceType["Room"] = "Room";
|
||||||
|
SpaceType["Amenity"] = "Amenity";
|
||||||
|
})(SpaceType || (exports.SpaceType = SpaceType = {}));
|
||||||
|
var BookingStatus;
|
||||||
|
(function (BookingStatus) {
|
||||||
|
BookingStatus["Available"] = "Available";
|
||||||
|
BookingStatus["Occupied"] = "Occupied";
|
||||||
|
BookingStatus["Reserved"] = "Reserved";
|
||||||
|
BookingStatus["OutOfService"] = "OutOfService";
|
||||||
|
})(BookingStatus || (exports.BookingStatus = BookingStatus = {}));
|
||||||
|
var UserRole;
|
||||||
|
(function (UserRole) {
|
||||||
|
UserRole["Admin"] = "Admin";
|
||||||
|
UserRole["Supervisor"] = "Supervisor";
|
||||||
|
UserRole["Employee"] = "Employee";
|
||||||
|
})(UserRole || (exports.UserRole = UserRole = {}));
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
export enum SpaceType {
|
||||||
|
Desk = 'Desk',
|
||||||
|
Room = 'Room',
|
||||||
|
Amenity = 'Amenity',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum BookingStatus {
|
||||||
|
Available = 'Available',
|
||||||
|
Occupied = 'Occupied',
|
||||||
|
Reserved = 'Reserved',
|
||||||
|
OutOfService = 'OutOfService',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum UserRole {
|
||||||
|
Admin = 'Admin',
|
||||||
|
Supervisor = 'Supervisor',
|
||||||
|
Employee = 'Employee',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SpaceDTO {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
type: SpaceType;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
status: BookingStatus;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"name": "@hot-desking/shared",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./",
|
||||||
|
"declaration": true,
|
||||||
|
"emitDeclarationOnly": false,
|
||||||
|
"module": "CommonJS",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"target": "ES2022"
|
||||||
|
},
|
||||||
|
"include": ["index.ts"]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
console.log('Happy developing ✨')
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Bundler",
|
||||||
|
"strict": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@shared/*": ["shared/*"]
|
||||||
|
},
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"esModuleInterop": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "CommonJS",
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "."
|
||||||
|
},
|
||||||
|
"include": ["src/**/*", "shared/**/*"]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue