diff --git a/README.md b/README.md index 00ac4df..3cbb3f6 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,19 @@ -# Warehouse +# Interview Homework -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.9. +Congratulations on making it through our awesome Talent Acquisition Team! You seem like a great candidate to join our team. Before the next round of interviews, we’d like to see some of your coding skills in action. -## Development server +## Backend -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. +The `backend/` folder contains the generated structure of an Express application, along with instructions for the functional requirements inside its [README](./backend/README.md). Please showcase your skills by developing a REST API for a Warehouse application. -## Code scaffolding +## Frontend -Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. +The `frontend/` folder contains the generated structure of an Angular application, along with instructions for the functional requirements inside its [README](./frontend/README.md). Please showcase your skills by developing a client-facing application for the Warehouse. -## Build +## Fullstack -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. +If you applied for a fullstack position, complete the assessment tasks for listing, adding, editing, and removing products in both the backend and frontend. -## Running unit tests +In the end, we should be able to test the implemented functionality of the backend through the frontend. This means you should start both the backend and frontend locally and use the Warehouse application to ensure everything works seamlessly. -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - -## Running end-to-end tests - -Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. - -## Further help - -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. +Good luck, and we look forward to seeing your work! diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 0000000..0711527 --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1,42 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# Compiled output +/dist +/tmp +/out-tsc +/bazel-out + +# Node +/node_modules +npm-debug.log +yarn-error.log + +# IDEs and editors +.idea/ +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# Miscellaneous +/.angular/cache +.sass-cache/ +/connect.lock +/coverage +/libpeerconnection.log +testem.log +/typings + +# System files +.DS_Store +Thumbs.db diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000..00d61e5 --- /dev/null +++ b/backend/README.md @@ -0,0 +1,34 @@ +# Express API for Warehouse app + +This folder serves as the scaffold of the application that is a part of the interview process for candidates attending on the position in CloudTalk. + +## Assignment + +1. Warehouse application, needs API for following features + 1. Table of products that are available + 2. Each item will have the following properties + 1. Quantity + 2. Unit price (euros) + 3. Shipments + 1. Possibility to create a new shipment + 1. Company name + 2. The generated ID of the shipment + 3. Creation date (generated) + 4. Scheduled shipment date + 5. Items + 2. Possibility to Edit the shipment + 3. The shipments are listed to preview + 4. Status + 1. each shipment will have 3 statuses + 1. Created + 2. Prepared + 3. Shipped +2. Please at the development consider + 1. Development best practises + 2. Testing + 3. Simulate a situation in which you work with the team (pay attention to how you work with Git) +3. This is a bare minimum, there are no limits to creativity, just keep in mind what we wanted + +We wish you good luck and a clear mind! We are looking forward to seeing you! + +PS: We should be able to run application locally, thus start the backend and be able to use endpoints through the curl/postman. diff --git a/backend/app.js b/backend/app.js new file mode 100644 index 0000000..d187f73 --- /dev/null +++ b/backend/app.js @@ -0,0 +1,20 @@ +var express = require('express'); +var path = require('path'); +var cookieParser = require('cookie-parser'); +var logger = require('morgan'); + +var indexRouter = require('./routes/index'); +var usersRouter = require('./routes/users'); + +var app = express(); + +app.use(logger('dev')); +app.use(express.json()); +app.use(express.urlencoded({ extended: false })); +app.use(cookieParser()); +app.use(express.static(path.join(__dirname, 'public'))); + +app.use('/', indexRouter); +app.use('/users', usersRouter); + +module.exports = app; diff --git a/backend/bin/www b/backend/bin/www new file mode 100755 index 0000000..76bd908 --- /dev/null +++ b/backend/bin/www @@ -0,0 +1,90 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var app = require('../app'); +var debug = require('debug')('warehouse-api:server'); +var http = require('http'); + +/** + * Get port from environment and store in Express. + */ + +var port = normalizePort(process.env.PORT || '3000'); +app.set('port', port); + +/** + * Create HTTP server. + */ + +var server = http.createServer(app); + +/** + * Listen on provided port, on all network interfaces. + */ + +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +/** + * Normalize a port into a number, string, or false. + */ + +function normalizePort(val) { + var port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ + +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + var bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ + +function onListening() { + var addr = server.address(); + var bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); +} diff --git a/backend/package-lock.json b/backend/package-lock.json new file mode 100644 index 0000000..05551d2 --- /dev/null +++ b/backend/package-lock.json @@ -0,0 +1,527 @@ +{ + "name": "warehouse-api", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "warehouse-api", + "version": "0.0.0", + "dependencies": { + "cookie-parser": "~1.4.4", + "debug": "~2.6.9", + "express": "~4.16.1", + "morgan": "~1.9.1" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha512-YQyoqQG3sO8iCmf8+hyVpgHHOv0/hCEFiS4zTGUwTA1HjAFX66wRcNQrVCeJq9pgESMRvUAOvSil5MJlmccuKQ==", + "dependencies": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "dependencies": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "dependencies": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha512-+IJOX0OqlHCszo2mBUq+SrEbCj6w7Kpffqx60zYbPTFaO4+yYgRjHwcZNpWvaTylDHaV7PPmBHzSecZiMhtPgw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "bin": { + "mime": "cli.js" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/morgan": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", + "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", + "dependencies": { + "basic-auth": "~2.0.0", + "debug": "2.6.9", + "depd": "~1.1.2", + "on-finished": "~2.3.0", + "on-headers": "~1.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "dependencies": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + } + } +} diff --git a/backend/package.json b/backend/package.json new file mode 100644 index 0000000..61df643 --- /dev/null +++ b/backend/package.json @@ -0,0 +1,14 @@ +{ + "name": "warehouse-api", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "node ./bin/www" + }, + "dependencies": { + "cookie-parser": "~1.4.4", + "debug": "~2.6.9", + "express": "~4.16.1", + "morgan": "~1.9.1" + } +} diff --git a/backend/public/index.html b/backend/public/index.html new file mode 100644 index 0000000..ab1ad8a --- /dev/null +++ b/backend/public/index.html @@ -0,0 +1,13 @@ + + + + Express + + + + +

Express

+

Welcome to Express

+ + + diff --git a/backend/public/stylesheets/style.css b/backend/public/stylesheets/style.css new file mode 100644 index 0000000..9453385 --- /dev/null +++ b/backend/public/stylesheets/style.css @@ -0,0 +1,8 @@ +body { + padding: 50px; + font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; +} + +a { + color: #00B7FF; +} diff --git a/backend/routes/index.js b/backend/routes/index.js new file mode 100644 index 0000000..ecca96a --- /dev/null +++ b/backend/routes/index.js @@ -0,0 +1,9 @@ +var express = require('express'); +var router = express.Router(); + +/* GET home page. */ +router.get('/', function(req, res, next) { + res.render('index', { title: 'Express' }); +}); + +module.exports = router; diff --git a/backend/routes/users.js b/backend/routes/users.js new file mode 100644 index 0000000..623e430 --- /dev/null +++ b/backend/routes/users.js @@ -0,0 +1,9 @@ +var express = require('express'); +var router = express.Router(); + +/* GET users listing. */ +router.get('/', function(req, res, next) { + res.send('respond with a resource'); +}); + +module.exports = router; diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..0711527 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,42 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# Compiled output +/dist +/tmp +/out-tsc +/bazel-out + +# Node +/node_modules +npm-debug.log +yarn-error.log + +# IDEs and editors +.idea/ +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# Miscellaneous +/.angular/cache +.sass-cache/ +/connect.lock +/coverage +/libpeerconnection.log +testem.log +/typings + +# System files +.DS_Store +Thumbs.db diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..9361a46 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,67 @@ +# Angular application for Warehouse + +This repository serves as the scaffold of the application that is a part of the interview process for candidates attending on the position in CloudTalk. + +## Assignment + +1. As a warehouse, we would like to have two main features + 1. Warehouse status + 1. Table of products that are available + 2. Each item will have the following properties + 1. Quantity + 2. Unit price (euros) + 2. Shipments + 1. Possibility to create a new shipment + 1. Company name + 2. The generated ID of the shipment + 3. Creation date (generated) + 4. Scheduled shipment date + 5. Items + 2. Possibility to Edit the shipment + 3. The shipments are listed to preview + 4. Status + 1. each shipment will have 3 statuses + 1. Created + 2. Prepared + 3. Shipped + 5. Creation/Editing of the shipment should be reflected in the warehouse status +2. The application should be prepared to use the REST API + 1. Data should be prepared in mocks, that will be used by the application + 2. In case of Fullstack position, the API should be implemented +3. Please at the development consider + 1. The development general + 2. Best practices for the development of angular application + 3. Testing + 4. Simulate a situation in which you work with the team (pay attention to how you work with Git) +4. This is a bare minimum, there are no limits to creativity, just keep in mind what we wanted + +We wish you good luck and a clear mind! We are looking forward to seeing you! + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.9. + +## Project informations + +### Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. + +### Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +### Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. + +### Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +### Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. + +### Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. + diff --git a/angular.json b/frontend/angular.json similarity index 98% rename from angular.json rename to frontend/angular.json index 2c9a054..3bd6d76 100644 --- a/angular.json +++ b/frontend/angular.json @@ -103,5 +103,8 @@ } } } + }, + "cli": { + "analytics": false } } diff --git a/karma.conf.js b/frontend/karma.conf.js similarity index 100% rename from karma.conf.js rename to frontend/karma.conf.js diff --git a/package-lock.json b/frontend/package-lock.json similarity index 99% rename from package-lock.json rename to frontend/package-lock.json index 9b2d81b..cd404ce 100644 --- a/package-lock.json +++ b/frontend/package-lock.json @@ -10567,9 +10567,9 @@ } }, "node_modules/socket.io-parser": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", - "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "dev": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", @@ -19584,9 +19584,9 @@ } }, "socket.io-parser": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", - "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "dev": true, "requires": { "@socket.io/component-emitter": "~3.1.0", diff --git a/package.json b/frontend/package.json similarity index 100% rename from package.json rename to frontend/package.json diff --git a/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts similarity index 57% rename from src/app/app-routing.module.ts rename to frontend/src/app/app-routing.module.ts index 0297262..8961090 100644 --- a/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -1,7 +1,13 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; +import {ItemsListComponent} from "./pages/items-list/items-list.component"; -const routes: Routes = []; +const routes: Routes = [ + { + path: '', + component: ItemsListComponent + } +]; @NgModule({ imports: [RouterModule.forRoot(routes)], diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html new file mode 100644 index 0000000..c40dd94 --- /dev/null +++ b/frontend/src/app/app.component.html @@ -0,0 +1,36 @@ + + + +
+ +
+ + diff --git a/frontend/src/app/app.component.scss b/frontend/src/app/app.component.scss new file mode 100644 index 0000000..5da529d --- /dev/null +++ b/frontend/src/app/app.component.scss @@ -0,0 +1,289 @@ +:host { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + font-size: 14px; + color: #333; + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 8px 0; +} + +p { + margin: 0; +} + +.spacer { + flex: 1; +} + +.toolbar { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 60px; + display: flex; + align-items: center; + background-color: #010833; + color: white; + font-weight: 600; + :last-child{ + margin-right: 16px; + } +} + +.toolbar img { + margin: 0 16px; +} + +.toolbar .social-logo { + height: 40px; + margin: 0 8px; +} + +.toolbar .social-logo:hover{ + opacity: 0.8; +} + +.content { + display: flex; + margin: 82px auto 32px; + padding: 0 16px; + max-width: 960px; + flex-direction: column; + align-items: center; +} + +svg.material-icons { + height: 24px; + width: auto; +} + +svg.material-icons:not(:last-child) { + margin-right: 8px; +} + +.card svg.material-icons path { + fill: #888; +} + +.card-container { + display: flex; + flex-wrap: wrap; + justify-content: center; + margin-top: 16px; +} + +.card { + all: unset; + border-radius: 4px; + border: 1px solid #eee; + background-color: #fafafa; + height: 40px; + width: 200px; + margin: 0 8px 16px; + padding: 16px; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + transition: all 0.2s ease-in-out; + line-height: 24px; +} + +.card-container .card:not(:last-child) { + margin-right: 0; +} + +.card.card-small { + height: 16px; + width: 168px; +} + +.card-container .card:not(.highlight-card) { + cursor: pointer; +} + +.card-container .card:not(.highlight-card):hover { + transform: translateY(-3px); + box-shadow: 0 4px 17px rgba(0, 0, 0, 0.35); +} + +.card-container .card:not(.highlight-card):hover .material-icons path { + fill: rgb(105, 103, 103); +} + +.card.highlight-card { + background-color: #1976d2; + color: white; + font-weight: 600; + border: none; + width: auto; + min-width: 30%; + position: relative; +} + +.card.card.highlight-card span { + margin-left: 60px; +} + +svg#rocket { + width: 80px; + position: absolute; + left: -10px; + top: -24px; +} + +svg#rocket-smoke { + height: calc(100vh - 95px); + position: absolute; + top: 10px; + right: 180px; + z-index: -10; +} + +a, +a:visited, +a:hover { + color: #1976d2; + text-decoration: none; +} + +a:hover { + color: #125699; +} + +.terminal { + position: relative; + width: 80%; + max-width: 600px; + border-radius: 6px; + padding-top: 45px; + margin-top: 8px; + overflow: hidden; + background-color: rgb(15, 15, 16); +} + +.terminal::before { + content: "\2022 \2022 \2022"; + position: absolute; + top: 0; + left: 0; + height: 4px; + background: rgb(58, 58, 58); + color: #c2c3c4; + width: 100%; + font-size: 2rem; + line-height: 0; + padding: 14px 0; + text-indent: 4px; +} + +.terminal pre { + font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; + color: white; + padding: 0 1rem 1rem; + margin: 0; +} + +.circle-link { + height: 40px; + width: 40px; + border-radius: 40px; + margin: 8px; + background-color: white; + border: 1px solid #eeeeee; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + transition: 1s ease-out; +} + +.circle-link:hover { + transform: translateY(-0.25rem); + box-shadow: 0px 3px 15px rgba(0, 0, 0, 0.2); +} + +footer { + margin-top: 8px; + display: flex; + align-items: center; + line-height: 20px; +} + +footer a { + display: flex; + align-items: center; +} + +.github-star-badge { + color: #24292e; + display: flex; + align-items: center; + font-size: 12px; + padding: 3px 10px; + border: 1px solid rgba(27,31,35,.2); + border-radius: 3px; + background-image: linear-gradient(-180deg,#fafbfc,#eff3f6 90%); + margin-left: 4px; + font-weight: 600; +} + +.github-star-badge:hover { + background-image: linear-gradient(-180deg,#f0f3f6,#e6ebf1 90%); + border-color: rgba(27,31,35,.35); + background-position: -.5em; +} + +.github-star-badge .material-icons { + height: 16px; + width: 16px; + margin-right: 4px; +} + +svg#clouds { + position: fixed; + bottom: -160px; + left: -230px; + z-index: -10; + width: 1920px; +} + +/* Responsive Styles */ +@media screen and (max-width: 767px) { + .card-container > *:not(.circle-link) , + .terminal { + width: 100%; + } + + .card:not(.highlight-card) { + height: 16px; + margin: 8px 0; + } + + .card.highlight-card span { + margin-left: 72px; + } + + svg#rocket-smoke { + right: 120px; + transform: rotate(-5deg); + } +} + +@media screen and (max-width: 575px) { + svg#rocket-smoke { + display: none; + visibility: hidden; + } +} \ No newline at end of file diff --git a/src/app/app.component.spec.ts b/frontend/src/app/app.component.spec.ts similarity index 100% rename from src/app/app.component.spec.ts rename to frontend/src/app/app.component.spec.ts diff --git a/src/app/app.component.ts b/frontend/src/app/app.component.ts similarity index 100% rename from src/app/app.component.ts rename to frontend/src/app/app.component.ts diff --git a/src/app/app.module.ts b/frontend/src/app/app.module.ts similarity index 100% rename from src/app/app.module.ts rename to frontend/src/app/app.module.ts diff --git a/frontend/src/app/core/models/warehouseItem.ts b/frontend/src/app/core/models/warehouseItem.ts new file mode 100644 index 0000000..1c8cbff --- /dev/null +++ b/frontend/src/app/core/models/warehouseItem.ts @@ -0,0 +1,8 @@ +export interface WarehouseItem { + imageUrl: string + id: number + name: string + description: string + quantity: number + unitPrice: number +} \ No newline at end of file diff --git a/frontend/src/app/pages/items-list/items-list.component.html b/frontend/src/app/pages/items-list/items-list.component.html new file mode 100644 index 0000000..377d83c --- /dev/null +++ b/frontend/src/app/pages/items-list/items-list.component.html @@ -0,0 +1,6 @@ +
+ + +
diff --git a/frontend/src/app/pages/items-list/items-list.component.scss b/frontend/src/app/pages/items-list/items-list.component.scss new file mode 100644 index 0000000..543b16c --- /dev/null +++ b/frontend/src/app/pages/items-list/items-list.component.scss @@ -0,0 +1,3 @@ +:host{ + width: 100%; +} \ No newline at end of file diff --git a/frontend/src/app/pages/items-list/items-list.component.spec.ts b/frontend/src/app/pages/items-list/items-list.component.spec.ts new file mode 100644 index 0000000..e632415 --- /dev/null +++ b/frontend/src/app/pages/items-list/items-list.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ItemsListComponent } from './items-list.component'; + +describe('ItemsListComponent', () => { + let component: ItemsListComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ ItemsListComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ItemsListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/pages/items-list/items-list.component.ts b/frontend/src/app/pages/items-list/items-list.component.ts new file mode 100644 index 0000000..6b5159a --- /dev/null +++ b/frontend/src/app/pages/items-list/items-list.component.ts @@ -0,0 +1,23 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import {ListItemComponent} from "./list-item/list-item.component"; +import {Observable, of} from "rxjs"; +import {WarehouseItem} from "../../core/models/warehouseItem"; +import {ItemsMockService} from "./items.mock.service"; + +@Component({ + selector: 'app-items-list', + standalone: true, + imports: [CommonModule, ListItemComponent], + templateUrl: './items-list.component.html', + styleUrls: ['./items-list.component.scss'] +}) +export class ItemsListComponent { + items$: Observable = this.itemsMockService.items + + constructor(private itemsMockService: ItemsMockService) { } + + addItemToShipment(id: number): void { + this.itemsMockService.addToShipment(id) + } +} diff --git a/frontend/src/app/pages/items-list/items.mock.service.spec.ts b/frontend/src/app/pages/items-list/items.mock.service.spec.ts new file mode 100644 index 0000000..aa4a576 --- /dev/null +++ b/frontend/src/app/pages/items-list/items.mock.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ItemsMockService } from './items.mock.service'; + +describe('ItemsMockService', () => { + let service: ItemsMockService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ItemsMockService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/pages/items-list/items.mock.service.ts b/frontend/src/app/pages/items-list/items.mock.service.ts new file mode 100644 index 0000000..2e1ac8c --- /dev/null +++ b/frontend/src/app/pages/items-list/items.mock.service.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; +import {Observable, of} from "rxjs"; +import {WarehouseItem} from "../../core/models/warehouseItem"; + +@Injectable({ + providedIn: 'root' +}) +export class ItemsMockService { + #mockedItems = [{ + id: 1, + imageUrl: 'assets/logo_black.svg', + name: 'CloudTalk logo sticker', + description: 'High-quality sticker of the best cloud calling solution provider in the world', + quantity: 100, + unitPrice: 1 + }] + + constructor() { } + + get items(): Observable { + return of(this.#mockedItems) + } + + addToShipment(id: number): void { + const item = this.#mockedItems.find(item => item.id === id) + // add to shipment logic + } +} diff --git a/frontend/src/app/pages/items-list/list-item/list-item.component.html b/frontend/src/app/pages/items-list/list-item/list-item.component.html new file mode 100644 index 0000000..fbee82d --- /dev/null +++ b/frontend/src/app/pages/items-list/list-item/list-item.component.html @@ -0,0 +1,12 @@ +
+
+ warehouse-item-image +
+
+ {{item.name}} + {{item.description}} +
+ {{item.quantity}}x + {{item.unitPrice | currency:'EUR'}} + +
\ No newline at end of file diff --git a/frontend/src/app/pages/items-list/list-item/list-item.component.scss b/frontend/src/app/pages/items-list/list-item/list-item.component.scss new file mode 100644 index 0000000..c75b4b7 --- /dev/null +++ b/frontend/src/app/pages/items-list/list-item/list-item.component.scss @@ -0,0 +1,26 @@ +:host{ + .list-item{ + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 10px; + &--image img{ + width: 50px; + height: 50px; + } + &--content{ + display: flex; + flex: 0.9; + flex-direction: column; + justify-content: space-around; + padding: 0 10px; + } + &--button{ + cursor: pointer; + border: 0; + border-radius: 7px; + padding: 10px; + } + } +} \ No newline at end of file diff --git a/frontend/src/app/pages/items-list/list-item/list-item.component.spec.ts b/frontend/src/app/pages/items-list/list-item/list-item.component.spec.ts new file mode 100644 index 0000000..f5f0767 --- /dev/null +++ b/frontend/src/app/pages/items-list/list-item/list-item.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ListItemComponent } from './list-item.component'; + +describe('ListItemComponent', () => { + let component: ListItemComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ ListItemComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ListItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/pages/items-list/list-item/list-item.component.ts b/frontend/src/app/pages/items-list/list-item/list-item.component.ts new file mode 100644 index 0000000..3d9a7a5 --- /dev/null +++ b/frontend/src/app/pages/items-list/list-item/list-item.component.ts @@ -0,0 +1,17 @@ +import {Component, EventEmitter, Input, Output} from '@angular/core'; +import { CommonModule } from '@angular/common'; +import {WarehouseItem} from "../../../core/models/warehouseItem"; + +@Component({ + selector: 'app-list-item', + standalone: true, + imports: [CommonModule], + templateUrl: './list-item.component.html', + styleUrls: ['./list-item.component.scss'] +}) +export class ListItemComponent { + @Input() item: WarehouseItem + @Output() addToShipment: EventEmitter = new EventEmitter() + + constructor() { } +} diff --git a/src/assets/.gitkeep b/frontend/src/assets/.gitkeep similarity index 100% rename from src/assets/.gitkeep rename to frontend/src/assets/.gitkeep diff --git a/frontend/src/assets/logo_black.svg b/frontend/src/assets/logo_black.svg new file mode 100644 index 0000000..f18371a --- /dev/null +++ b/frontend/src/assets/logo_black.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/symbol_white.svg b/frontend/src/assets/symbol_white.svg new file mode 100644 index 0000000..fbc2c7a --- /dev/null +++ b/frontend/src/assets/symbol_white.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/environments/environment.prod.ts b/frontend/src/environments/environment.prod.ts similarity index 100% rename from src/environments/environment.prod.ts rename to frontend/src/environments/environment.prod.ts diff --git a/src/environments/environment.ts b/frontend/src/environments/environment.ts similarity index 100% rename from src/environments/environment.ts rename to frontend/src/environments/environment.ts diff --git a/src/favicon.ico b/frontend/src/favicon.ico similarity index 100% rename from src/favicon.ico rename to frontend/src/favicon.ico diff --git a/src/index.html b/frontend/src/index.html similarity index 100% rename from src/index.html rename to frontend/src/index.html diff --git a/src/main.ts b/frontend/src/main.ts similarity index 100% rename from src/main.ts rename to frontend/src/main.ts diff --git a/src/polyfills.ts b/frontend/src/polyfills.ts similarity index 100% rename from src/polyfills.ts rename to frontend/src/polyfills.ts diff --git a/src/styles.scss b/frontend/src/styles.scss similarity index 100% rename from src/styles.scss rename to frontend/src/styles.scss diff --git a/src/test.ts b/frontend/src/test.ts similarity index 100% rename from src/test.ts rename to frontend/src/test.ts diff --git a/tsconfig.app.json b/frontend/tsconfig.app.json similarity index 100% rename from tsconfig.app.json rename to frontend/tsconfig.app.json diff --git a/tsconfig.json b/frontend/tsconfig.json similarity index 95% rename from tsconfig.json rename to frontend/tsconfig.json index ff06eae..cbbfff7 100644 --- a/tsconfig.json +++ b/frontend/tsconfig.json @@ -6,6 +6,7 @@ "outDir": "./dist/out-tsc", "forceConsistentCasingInFileNames": true, "strict": true, + "strictPropertyInitialization": false, "noImplicitOverride": true, "noPropertyAccessFromIndexSignature": true, "noImplicitReturns": true, diff --git a/tsconfig.spec.json b/frontend/tsconfig.spec.json similarity index 100% rename from tsconfig.spec.json rename to frontend/tsconfig.spec.json diff --git a/src/app/app.component.html b/src/app/app.component.html deleted file mode 100644 index 2a0fbf1..0000000 --- a/src/app/app.component.html +++ /dev/null @@ -1,484 +0,0 @@ - - - - - - - - - - - - - - -
- - -
- - - Rocket Ship - - - - - - - - - - {{ title }} app is running! - - - Rocket Ship Smoke - - - -
- - -

Resources

-

Here are some links to help you get started:

- - - - -

Next Steps

-

What do you want to do next with your app?

- - - -
- - - - - - - - - - - -
- - -
-
ng generate component xyz
-
ng add @angular/material
-
ng add @angular/pwa
-
ng add _____
-
ng test
-
ng build
-
- - - - - - - - - Gray Clouds Background - - - -
- - - - - - - - - - diff --git a/src/app/app.component.scss b/src/app/app.component.scss deleted file mode 100644 index e69de29..0000000