docs: configurando deploy via ssh para angular

This commit is contained in:
2026-01-02 19:55:27 -05:00
parent a16d0f0701
commit b0beb50d59
544 changed files with 97696 additions and 0 deletions

16
.editorconfig Normal file
View File

@@ -0,0 +1,16 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
[*.md]
max_line_length = off
trim_trailing_whitespace = false

49
.gitignore vendored Normal file
View File

@@ -0,0 +1,49 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out
# dependencies
/node_modules
# profiling files
chrome-profiler-events*.json
speed-measure-plugin*.json
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db
*.rar
.vercel

148
angular.json Normal file
View File

@@ -0,0 +1,148 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"sales": {
"projectType": "application",
"schematics": {"@schematics/angular:component": {
"style": "scss"
}},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/sales",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": [
"src/favicon.ico",
"src/assets",
"src/assets/web.config",
"src/assets/banners",
"src/assets/icones",
"src/assets/img"
],
"styles": [
{
"input": "node_modules/bootstrap/dist/css/bootstrap.min.css"
},
"node_modules/bootstrap-icons/font/bootstrap-icons.css",
"node_modules/@progress/kendo-theme-bootstrap/dist/all.css",
"src/styles.css",
"src/styles-menu.css"
],
"scripts": [
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
"node_modules/jquery/dist/jquery.min.js"
]
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "10mb",
"maximumError": "12mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "10kb",
"maximumError": "12kb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "sales:build"
},
"configurations": {
"production": {
"browserTarget": "sales:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "sales:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets",
"src/assets/web.config",
"src/assets/banners",
"src/assets/icones",
"src/assets/img"
],
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"node_modules/bootstrap-icons/font/bootstrap-icons.css",
"node_modules/line-awesome/dist/line-awesome/css/line-awesome.min.css",
"src/styles.css",
"src/styles-menu.css"
],
"scripts": ["node_modules/jquery/dist/jquery.min.js"]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "sales:serve"
},
"configurations": {
"production": {
"devServerTarget": "sales:serve:production"
}
}
}
}
}
},
"defaultProject": "sales"
}

12
browserslist Normal file
View File

@@ -0,0 +1,12 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.

32
e2e/protractor.conf.js Normal file
View File

@@ -0,0 +1,32 @@
// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/**/*.e2e-spec.ts'
],
capabilities: {
browserName: 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.json')
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

23
e2e/src/app.e2e-spec.ts Normal file
View File

@@ -0,0 +1,23 @@
import { AppPage } from './app.po';
import { browser, logging } from 'protractor';
describe('workspace-project App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getTitleText()).toEqual('sales app is running!');
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
});
});

11
e2e/src/app.po.ts Normal file
View File

@@ -0,0 +1,11 @@
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo(): Promise<unknown> {
return browser.get(browser.baseUrl) as Promise<unknown>;
}
getTitleText(): Promise<string> {
return element(by.css('app-root .content span')).getText() as Promise<string>;
}
}

13
e2e/tsconfig.json Normal file
View File

@@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

38
gitea/deploy-ssh.yaml Normal file
View File

@@ -0,0 +1,38 @@
name: Deploy Angular via SSH
on: [push]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node 16
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install and Build
run: |
npm install --legacy-peer-deps
npm run build -- --prod
- name: Transferir arquivos via SCP
uses: https://github.com/appleboy/scp-action@master
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: "dist/"
target: "/var/www/html/vendaweb-frontend"
strip_components: 1
- name: Reiniciar Nginx Remoto
uses: https://github.com/appleboy/ssh-action@master
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
sudo systemctl reload nginx

32
karma.conf.js Normal file
View File

@@ -0,0 +1,32 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, './coverage/sales'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};

1
kendo-ui-license.txt Normal file
View File

@@ -0,0 +1 @@
eyJhbGciOiJSUzI1NiIsInR5cCI6IkxJQyJ9.eyJwcm9kdWN0cyI6W3sidHJpYWwiOnRydWUsImNvZGUiOiJLRU5ET1VJQU5HVUxBUiIsImxpY2Vuc2VFeHBpcmF0aW9uRGF0ZSI6MTYyMjc5NTQwMX1dLCJpbnRlZ3JpdHkiOiJVZ3JzZnhGQ0tjcExXQlY1Wm5UV3RRMXNEc1U9IiwibGljZW5zZUhvbGRlciI6ImVkdWFyZG8uZXN0ZXZhb0BhcHBzb2x1dGkuY29tLmJyIiwiaWF0IjoxNjIwODM0NDQ0LCJhdWQiOiJlZHVhcmRvLmVzdGV2YW9AYXBwc29sdXRpLmNvbS5iciJ9.FkYEcMVlG6LO6oGZiBC6yuHBiVXPm4ebPBeLmZ-r71xIZyGwzf1NIERIbDx9akyQXVSup9vST7nx5SIfIBYopkeWYBHLv6ps7-_omU0PI8T6lRw1QMIhqJ4qMVglUwR7vaQssPYOkJUZXJ6PJxDg-AJSRgc1mpWmErjyqpC0rxMlpAJCJZNP21OSithU4MEwYCBS3O-MaN8JhsMzg6z0cBKHvYsrPFvubUDBWBcwj4wEPPEGv1f7QVpglZME4Z7ZIXvJT9bEQC71OGa9Y7vjyuWBsStl0N3a8GMOhxks2semBHsRv7zb4ZMaRouqK2ZOHT6tdjhD5imWxz1_nIDvPw

38395
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

105
package.json Normal file
View File

@@ -0,0 +1,105 @@
{
"name": "sales",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve --host 0.0.0.0",
"build": "ng build --prod && npx kendo-ui-license activate",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@agm/core": "^1.1.0",
"@angular/animations": "^9.1.13",
"@angular/common": "^9.1.13",
"@angular/compiler": "~9.1.13",
"@angular/core": "^9.1.13",
"@angular/fire": "^6.1.5",
"@angular/forms": "^9.1.13",
"@angular/localize": "^9.1.13",
"@angular/platform-browser": "~9.1.13",
"@angular/platform-browser-dynamic": "~9.1.13",
"@angular/router": "~9.1.13",
"@ngrx/effects": "^9.2.1",
"@ngrx/store": "^9.2.1",
"@ngrx/store-devtools": "^12.0.0",
"@popperjs/core": "^2.11.8",
"@progress/kendo-angular-barcodes": "^1.0.0",
"@progress/kendo-angular-buttons": "^7.0.2",
"@progress/kendo-angular-charts": "^6.0.1",
"@progress/kendo-angular-common": "^2.0.0",
"@progress/kendo-angular-dateinputs": "^6.0.0",
"@progress/kendo-angular-dialog": "^6.0.1",
"@progress/kendo-angular-dropdowns": "^6.0.1",
"@progress/kendo-angular-excel-export": "^4.0.3",
"@progress/kendo-angular-gauges": "^4.1.3",
"@progress/kendo-angular-grid": "^6.0.1",
"@progress/kendo-angular-icons": "^0.4.5",
"@progress/kendo-angular-indicators": "^1.1.2",
"@progress/kendo-angular-inputs": "^8.0.9",
"@progress/kendo-angular-intl": "^3.0.0",
"@progress/kendo-angular-l10n": "^3.0.0",
"@progress/kendo-angular-label": "^3.1.2",
"@progress/kendo-angular-layout": "^6.4.2",
"@progress/kendo-angular-listview": "^3.0.0",
"@progress/kendo-angular-menu": "^3.0.4",
"@progress/kendo-angular-navigation": "^1.1.4",
"@progress/kendo-angular-notification": "^3.0.5",
"@progress/kendo-angular-pager": "^3.0.1",
"@progress/kendo-angular-pdf-export": "^3.0.3",
"@progress/kendo-angular-popup": "^4.0.0",
"@progress/kendo-angular-progressbar": "^2.0.3",
"@progress/kendo-angular-scrollview": "^4.1.3",
"@progress/kendo-angular-tooltip": "^3.1.5",
"@progress/kendo-angular-treeview": "^6.0.0",
"@progress/kendo-data-query": "^1.5.5",
"@progress/kendo-drawing": "^1.1.2",
"@progress/kendo-licensing": "^1.0.2",
"@progress/kendo-svg-icons": "^0.1.2",
"@progress/kendo-theme-bootstrap": "^5.1.1",
"@progress/kendo-theme-default": "^5.1.1",
"bootstrap": "^5.0.0-beta3",
"bootstrap-icons": "^1.7.2",
"chart.js": "^2.9.4",
"cldr-data": "^36.0.1",
"firebase": "^8.6.2",
"hammerjs": "^2.0.0",
"jwt-decode": "^3.1.2",
"line-awesome": "^1.3.0",
"lottie-web": "^5.12.2",
"ng2-charts": "^2.3.0",
"ngx-bootstrap": "^8.0.0",
"ngx-currency": "^2.5.3",
"ngx-lottie": "^7.0.3",
"rxjs": "^6.5.5",
"stimulsoft-viewer-angular": "^2020.5.2",
"tslib": "^1.10.0",
"zone.js": "~0.10.2"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.901.15",
"@angular/cli": "~9.1.15",
"@angular/compiler-cli": "~9.1.13",
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3",
"@types/jquery": "^3.5.5",
"@types/node": "^12.11.1",
"codelyzer": "^5.1.2",
"install": "^0.13.0",
"jasmine-core": "^3.5.0",
"jasmine-spec-reporter": "~4.2.1",
"jquery": "^3.6.0",
"karma": "^5.0.9",
"karma-chrome-launcher": "^3.1.1",
"karma-coverage-istanbul-reporter": "~2.1.0",
"karma-jasmine": "^3.0.3",
"karma-jasmine-html-reporter": "^1.7.0",
"npm": "^7.13.0",
"protractor": "~7.0.0",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",
"typescript": "^3.8.3"
}
}

View File

@@ -0,0 +1,30 @@
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from '../guards/auth.guard';
import { KendoModule } from '../shared/kendo.module';
import { LottieModule } from 'ngx-lottie';
import player from 'lottie-web';
import { PermissionUserComponent } from './permission-user/permission-user.component';
import { ComponentModule } from '../components/component.module'; // Importando o módulo correto
export function playerFactory() {
return player;
}
const routes: Routes = [
{ path: 'permission-user', component: PermissionUserComponent, canActivate: [AuthGuard] },
];
@NgModule({
imports: [
CommonModule,
RouterModule.forChild(routes),
KendoModule,
LottieModule.forRoot({ player: playerFactory }),
ComponentModule, // Importa o módulo que contém HeaderAdminComponent
],
declarations: [PermissionUserComponent], // Apenas componentes exclusivos deste módulo
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AdminModule {}

View File

@@ -0,0 +1,63 @@
<app-header-admin></app-header-admin>
<div class="d-flex flex-column wrapper">
<main class="flex-fill main-dashboard">
<div class="container">
<div class="title-page">
<span>Selecione o usuário</span>
</div>
<div class="row">
<div class="col-sm-12 col-md-8">
<kendo-combobox (selectionChange)="getPermissionUser()" (valueChange)="setUserSelected($event)"
[valueNormalizer]="valueNormalizer" [data]="users" [kendoDropDownFilter]="filterSettings" textField="name"
valueField="userId" placeholder="Selecione o usuário..." (input)="forceUppercase($event)">
</kendo-combobox>
</div>
<div class="col-sm-12 col-md-2">
<button kendoButton class="btn-form" [disabled]="!userSelected" [icon]="isLoading ? 'loading' : ''"
(click)="getPermissionUser()">Pesquisar Permissões</button>
</div>
<div class="col-sm-12 col-md-2">
<button *ngIf="permissions.length > 0" kendoButton class="btn-form" [disabled]="!userSelected"
(click)="savePermissions()">Salvar
Permissões</button>
</div>
</div>
<div class="flex-fill">
<div *ngIf="userSelected && permissions.length; else noUserSelected">
<kendo-treeview
[nodes]="permissions"
[children]="children"
[hasChildren]="hasChildren"
textField="text"
kendoTreeViewCheckable
[(checkedKeys)]="checkedKeys">
</kendo-treeview>
</div>
<ng-template #noUserSelected>
<div class="noData">
<ng-lottie *ngIf="lottieOptions" [options]="lottieOptions" [styles]="lottieStyles"></ng-lottie>
<p class="text-muted" *ngIf="!isLoading">
{{ infoMessage }}
</p>
</div>
</ng-template>
</div>
</div>
</main>
<footer>
<div class="container-fluid home-footer">
<div class="row align-items-center justify-content-center">
<div class="col-12">
<span class="text-center text-footer">
&copy; 2022 App Soluti Soluções em aplicativos moveis
</span>
</div>
</div>
</div>
</footer>
</div>

View File

@@ -0,0 +1,363 @@
.wrapper {
height: 100vh;
}
.logo {
background-image: url("../../../assets/img/logo.svg");
background-position: center;
cursor: pointer;
width: 100%;
height: 80px !important;
overflow: hidden;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
.header-productlist {
display: flex;
flex-direction: row;
align-items: center;
padding: 32px 64px;
width: 100%;
height: 80px;
position: absolute;
width: 100%;
height: 80px;
top: 0px;
margin: 0px;
/*background: #2d2e83;*/
background: #131d52;
}
.header-menu {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
position: static;
height: 48px;
background: #1d1e67;
border-radius: 5px;
/* Inside auto layout */
flex: none;
order: 1;
flex-grow: 0;
}
.name-user {
position: static;
width: 100%;
font-family: "Open Sans";
font-style: normal;
font-weight: 700;
font-size: 12px;
line-height: 19px;
/* identical to box height */
color: #ffffff;
/* Inside auto layout */
flex: none;
order: 0;
flex-grow: 0;
margin: 0px 0px;
}
.last-access {
position: static;
font-family: "Open Sans";
font-style: normal;
font-weight: 400;
font-size: 10px;
line-height: 16px;
color: #848484;
/* Inside auto layout */
flex: none;
order: 1;
flex-grow: 0;
margin: 0px 0px;
}
.img-config {
position: static;
background: #ffffff;
flex: none;
order: 2;
flex-grow: 0;
margin: 0px 16px;
}
.center {
// modificado
position: relative;
top: 50%;
transform: translateY(-50%);
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
flex-direction: column;
text-align: center;
}
.img-user {
position: static;
width: 36px;
height: 36px;
left: 8px;
top: 6px;
background: url("../../../assets/img/img_user.svg");
border-radius: 2px;
/* Inside auto layout */
flex: none;
order: 0;
flex-grow: 0;
margin: 0px 16px;
}
.home-footer {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 100%;
height: 46px;
/*background: #2d2e83;*/
background: #131d52;
}
.text-footer {
position: static;
font-family: "Open Sans";
font-style: normal;
font-weight: 400;
font-size: 10px;
line-height: 14px;
/* identical to box height */
text-align: center;
color: #ffffff;
flex: none;
order: 0;
flex-grow: 0;
}
.main-dashboard {
margin-top: 80px;
}
.new-order {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 100%;
height: 40px;
position: static;
background: #ff9521;
border-radius: 5px;
/* Inside auto layout */
flex: none;
order: 1;
flex-grow: 0;
border-radius: 5px;
}
.text-button {
position: static;
font-family: "Open Sans";
font-style: normal;
font-weight: 700;
font-size: 16px;
line-height: 22px;
/* identical to box height */
text-align: center;
color: #ffffff;
/* Inside auto layout */
flex: none;
order: 0;
flex-grow: 0;
}
.button-flat {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 100%;
height: 40px;
position: static;
background: #ffffff;
border: 1px solid #ef7d00;
box-sizing: border-box;
border-radius: 5px;
/* Inside auto layout */
flex: none;
order: 1;
flex-grow: 0;
}
.side-menu {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
padding: 16px;
position: static;
height: 100%;
left: 0px;
top: 0px;
background: #ffffff;
/* Inside auto layout */
flex: none;
order: 0;
align-self: stretch;
flex-grow: 0;
margin: 0px 0px;
}
.text-button-flat {
position: static;
font-family: "Open Sans";
font-style: normal;
font-weight: 700;
font-size: 16px;
line-height: 22px;
/* identical to box height */
text-align: center;
color: #ef7d00;
/* Inside auto layout */
flex: none;
order: 0;
flex-grow: 0;
}
.button-flat-blue {
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 0px;
position: static;
width: 100%;
height: 40px;
background: #ffffff;
border: 1px solid #2d2e83;
box-sizing: border-box;
border-radius: 5px;
/* Inside auto layout */
flex: none;
order: 1;
align-self: stretch;
flex-grow: 0;
}
.text-button-flat-blue {
position: static;
font-family: "Open Sans";
font-style: normal;
font-weight: 700;
font-size: 16px;
line-height: 22px;
/* identical to box height */
text-align: center;
color: #2d2e83;
/* Inside auto layout */
flex: none;
order: 0;
flex-grow: 0;
}
.noData {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
flex-direction: column;
text-align: center;
}
.text-muted{
font-size: 14px;
}
/* Responsividade */
/* Smartphones */
@media (max-width: 575.98px) {
.btnSbtn-formearch {
margin-top: 10px;
width: 100%;
}
.title-page{
margin-top: 10px;
}
.noData {
padding: 10px;
}
.noData p {
font-size: 14px;
}
}
/* Tablets */
@media (max-width: 991.98px) {
.btn-form {
margin-top: 10px;
width: 100%;
}
.title-page{
margin-top: 10px;
}
}
/* Desktops */
@media (min-width: 992px) {
.btn-form {
max-width: 200px;
}
.title-page{
margin-top: 10px;
}
}

View File

@@ -0,0 +1,192 @@
import { Component, OnInit } from '@angular/core';
import { DropDownFilterSettings } from '@progress/kendo-angular-dropdowns';
import { Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { AuthService } from 'src/app/auth/services/auth.service';
import { UserService } from 'src/app/services/user.service';
import { process } from '@progress/kendo-data-query';
import { AnimationOptions } from 'ngx-lottie';
@Component({
selector: 'app-permission-user',
templateUrl: './permission-user.component.html',
styleUrls: ['./permission-user.component.scss']
})
export class PermissionUserComponent implements OnInit {
/* Header */
public userName: string;
public storeName: string;
users: any[] = [];
public checkedKeys: any[] = [];
public data: any[] = [];
public userSelected: any;
public children = (dataItem: any): Observable<any[]> => of(dataItem.items);
public hasChildren = (dataItem: any): boolean => !!dataItem.items;
public permissions: any[] = [];
public isUserLoading = false;
public loadingIcon = '';
public isLoading = false;
public infoMessage = 'Por favor, selecione um usuário para carregar as permissões.';
public lottieOptions: AnimationOptions = {
path: 'assets/animations/no-data.json',
};
public lottieStyles = {
width: '300px',
height: '300px',
};
constructor(private readonly authService: AuthService,
private readonly userService: UserService) { }
ngOnInit() {
this.userName = this.authService.getUserName();
this.storeName = this.authService.getStoreName();
this.userService.getUsers()
.pipe(
map((users) => {
this.users = users;
}))
.subscribe();
if (!this.userSelected) {
this.infoMessage = 'Nenhum usuário está selecionado.';
}
this.loadUsers();
}
loadUsers() {
this.isUserLoading = true;
this.userService.getUsers()
.pipe(
map((users) => {
this.users = users;
this.isUserLoading = false;
}),
catchError((error) => {
console.error('Erro ao carregar usuários:', error);
this.isUserLoading = false;
return of([]);
})
)
.subscribe();
}
logout() {
this.authService.logout();
}
public filterSettings: DropDownFilterSettings = {
caseSensitive: false,
operator: "contains",
};
public valueNormalizer = (text: Observable<string>) =>
text.pipe(
map((content: string) => {
return {
value: this.permissions[this.permissions.length - 1]?.value + 1 || 1,
text: content,
};
})
);
forceUppercase(event: Event): void {
const inputElement = event.target as HTMLInputElement;
if (inputElement && inputElement.value) {
inputElement.value = inputElement.value.toUpperCase();
}
}
setUserSelected(user: any) {
console.log(user);
this.userSelected = user;
if (!user) {
this.permissions = [];
this.checkedKeys = [];
this.infoMessage = 'Por favor, selecione um usuário válido.';
} else {
this.checkedKeys = [];
this.infoMessage = '';
}
}
getPermissionUser() {
if (!this.userSelected) {
console.warn('Nenhum usuário selecionado. Não é possível buscar permissões.');
this.lottieOptions = { path: 'assets/animations/no-data.json' };
return;
}
this.isLoading = true;
this.lottieOptions = { path: 'assets/animations/loading.json' };
this.userService.getPermissionUser(this.userSelected.userId)
.pipe(
map((permissions) => {
this.permissions = permissions;
this.loadPermissions(this.permissions);
// If permissions are found, stop the loading animation
this.isLoading = false;
this.lottieOptions = permissions.length > 0
? { path: 'assets/animations/no-data.json' }
: { path: 'assets/animations/no-data.json' };
}),
catchError((error) => {
console.error('Erro ao carregar permissões do usuário:', error);
this.isLoading = false; // Stop loading state
this.lottieOptions = { path: 'assets/animations/no-data.json' }; // Error or no data animation
return of([]); // Default return value in case of error
})
)
.subscribe();
}
savePermissions() {
const permissionsId: number[] = [];
const atividades: any[] = [];
const actions: any[] = [];
for (const key of this.checkedKeys) {
const ids = key.split("_");
if (ids.length > 2) {
const module = this.permissions[ids[0]];
const atividade = module.items[ids[1]];
const action = atividade.items[ids[2]];
if (action != undefined) {
actions.push(action);
}
} else {
const module = this.permissions[ids[0]];
const atividade = module.items[ids[1]];
if (atividade != undefined) {
atividades.push(atividade);
}
}
}
const updatePermissions = { atividades: atividades, actions: actions };
const userId = this.userSelected.userId;
this.userService.updatePermissionUser(userId, updatePermissions);
}
loadPermissions(data: any) {
this.checkedKeys = [];
data.filter(permission => permission.allow == 'S')
.forEach(permissionModule => {
let indice_modulo = -1;
let indice_atividade = -1;
permissionModule.items
.filter(permissionAtividade => permissionAtividade.allow == 'S')
.forEach(permissionAtividade => {
indice_modulo++;
indice_atividade++;
this.checkedKeys.push(`${indice_modulo}_${indice_atividade}`);
});
});
}
}

View File

@@ -0,0 +1,26 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuard } from './guards/auth.guard';
import { MenuComponent } from './menu/menu.component';
import { MenuEcosistemaComponent } from './menu-ecosistema/menu-ecosistema.component';
const routes: Routes = [
{ path: '', redirectTo: 'sales/home', pathMatch: 'full' },
// loadChildren: () => import('./sales/sales.module').then(m => m.SalesModule), canActivate: [AuthGuard] },
{ path: 'login', loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule)},
{ path: 'menu', component: MenuEcosistemaComponent},
{ path: 'financial', loadChildren: () => import('./financial/financial.module').then(m => m.FinancialModule), canActivate: [AuthGuard] },
{ path: 'sales', loadChildren: () => import('./sales/sales.module').then(m => m.SalesModule), canActivate: [AuthGuard] },
{ path: 'crm', loadChildren: () => import('./crm/crm.module').then(m => m.CrmModule), canActivate: [AuthGuard] },
{ path: 'partner', loadChildren: () => import('./partners/partners.module').then(m => m.PartnersModule), canActivate: [AuthGuard] },
{ path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule), canActivate: [AuthGuard] },
{ path: 'dashboardcompany', loadChildren: () =>
import('./sales/pages/dashboard-company/dashboard-company.module').then(m => m.DashboardCompanyModule)},
];
@NgModule({
imports: [RouterModule.forRoot(routes, {useHash: true})],
exports: [RouterModule]
})
export class AppRoutingModule { }

View File

View File

@@ -0,0 +1 @@
<router-outlet></router-outlet>

View File

@@ -0,0 +1,35 @@
import { TestBed, async } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'sales'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('sales');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('.content span').textContent).toContain('sales app is running!');
});
});

10
src/app/app.component.ts Normal file
View File

@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'sales';
}

103
src/app/app.module.ts Normal file
View File

@@ -0,0 +1,103 @@
import { BrowserModule } from '@angular/platform-browser';
import { DEFAULT_CURRENCY_CODE, LOCALE_ID, NgModule } from '@angular/core';
import ptBr from '@angular/common/locales/pt';
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { LottieModule } from 'ngx-lottie';
import player from 'lottie-web';
import { SalesModule } from './sales/sales.module';
import { FinancialModule } from './financial/financial.module';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '../environments/environment';
import { EffectsModule } from '@ngrx/effects';
import { ShoppingEffects } from './sales/store/effects/shopping.effects';
import { StoreModule } from '@ngrx/store';
import { ShoppingReducer } from './sales/store/reducers/shopping.reducer';
import { AngularFireModule } from '@angular/fire';
import { AngularFirestoreModule } from '@angular/fire/firestore';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AuthGuard } from './guards/auth.guard';
import { AuthService } from './auth/services/auth.service';
import { CustomerModule } from './sales/customer/customer.module';
import { KendoModule } from './shared/kendo.module';
import { MessageErrorComponent } from './shared/menssages/message-error/message-error.component';
import { MenuEcosistemaComponent } from './menu-ecosistema/menu-ecosistema.component';
import { ComponentModule } from './components/component.module';
import { MessageFailureComponent } from './shared/menssages/message-failure/message-failure.component';
import { CustomerSaleEffects } from './sales/store/effects/customer-sale.effects';
import { CustomerSaleReducer } from './sales/store/reducers/customer-sale.reducer';
import { MenssageInformationComponent } from './shared/menssages/menssage-information/menssage-information.component';
import { CrmModule } from './crm/crm.module';
import { registerLocaleData } from '@angular/common';
import { MenuComponent } from './menu/menu.component';
import { MenuSalesComponent } from './sales/menu-sales/menu-sales.component';
import { StimulsoftViewerModule } from 'stimulsoft-viewer-angular';
import { DialogRef } from '@progress/kendo-angular-dialog';
import { PartnersModule } from './partners/partners.module';
import { AdminModule } from './admin/admin.module';
import { DialogsModule } from '@progress/kendo-angular-dialog';
import { ChartsModule } from '@progress/kendo-angular-charts';
import 'hammerjs';
registerLocaleData(ptBr);
export function playerFactory() {
return player;
}
@NgModule({
declarations: [
AppComponent,
MessageErrorComponent,
MessageFailureComponent,
MenuEcosistemaComponent,
MenssageInformationComponent,
MenuComponent,
MenuSalesComponent,
],
imports: [
AngularFireModule.initializeApp(environment.firebase),
DialogsModule,
AngularFirestoreModule, // imports firebase/firestore, only needed for database features
AngularFireAuthModule,
BrowserModule,
HttpClientModule,
FinancialModule,
AppRoutingModule,
BrowserAnimationsModule,
SalesModule,
CustomerModule,
KendoModule,
ComponentModule,
CrmModule,
StoreModule.forRoot({ shopping: ShoppingReducer, customerSale: CustomerSaleReducer }),
EffectsModule.forRoot([ShoppingEffects, CustomerSaleEffects]),
StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: environment.production }),
StimulsoftViewerModule,
PartnersModule,
AdminModule,
// LottieModule.forRoot({ player: playerFactory }),
ChartsModule,
],
exports: [StimulsoftViewerModule],
providers: [
AuthGuard, AuthService,
{ provide: LocationStrategy, useClass: HashLocationStrategy },
{ provide: LOCALE_ID, useValue: 'pt-BR' },
{ provide: DEFAULT_CURRENCY_CODE, useValue: 'BRL', },
DialogRef,
/*{
provide: ErrorHandler,
useClass: ErrorsHandler,
},*/
],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@@ -0,0 +1,9 @@
.example {
display: flex;
justify-content: center;
}
.k-form kendo-label:not(:last-of-type) {
flex-direction: column;
margin-bottom: 10px;
}

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AuthLoginComponent } from './auth-login.component';
describe('AuthLoginComponent', () => {
let component: AuthLoginComponent;
let fixture: ComponentFixture<AuthLoginComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AuthLoginComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AuthLoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,65 @@
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-auth-login',
templateUrl: './auth-login.component.html',
styleUrls: ['./auth-login.component.scss',
'./auth-login.component.css']
})
export class AuthLoginComponent implements OnInit {
public phoneNumberValue = '';
public phoneNumberMask = '(999) 000-00-00-00';
public form: FormGroup;
public data: any = {
fullName: '',
email: '',
phoneNumber: this.phoneNumberValue,
arrivalDate: null,
numberOfNights: null,
numberOfGuests: null,
terms: false,
comments: '',
};
constructor() {
this.form = new FormGroup({
fullName: new FormControl(this.data.fullName, [Validators.required]),
email: new FormControl(this.data.email, [
Validators.required,
Validators.email,
]),
phoneNumber: new FormControl(this.data.phoneNumber, [
Validators.required,
]),
arrivalDate: new FormControl(this.data.arrivalDate, [
Validators.required,
]),
numberOfNights: new FormControl(this.data.numberOfNights, [
Validators.required,
]),
numberOfGuests: new FormControl(this.data.numberOfGuests, [
Validators.required,
Validators.max(5),
]),
terms: new FormControl(this.data.terms, [Validators.requiredTrue]),
comments: new FormControl(this.data.comments),
});
}
ngOnInit(): void {
}
public submitForm(): void {
this.form.markAllAsTouched();
}
public clearForm(): void {
this.form.reset();
}
}

View File

@@ -0,0 +1,25 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AuthLoginComponent } from './auth-login/auth-login.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { KendoModule } from '../shared/kendo.module';
import { LoginComponent } from './login/login.component';
import { RouterModule, Routes } from '@angular/router';
import { RegisterComponent } from './register/register.component';
import { AuthService } from './services/auth.service';
const routes: Routes = [{ path: '', component: LoginComponent },
{ path: 'register', component: RegisterComponent }];
@NgModule({
declarations: [AuthLoginComponent, LoginComponent, RegisterComponent],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
KendoModule,
RouterModule.forChild(routes),
],
providers: [AuthService]
})
export class AuthModule { }

View File

@@ -0,0 +1,206 @@
.hs-login {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 32px 64px;
position: absolute;
background: #fcfcfc;
}
.logo {
width: 190px;
height: 51.54px;
}
.fs-login {
display: flex;
flex-direction: column;
align-items: flex-start;
/* width: 100%; */
}
.fs-label {
display: flex;
width: 100%;
}
.container-login {
background-image: url("../../../assets/img/Background.png");
background-size: cover;
height: 100vh;
}
.cs-login {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 60px 40px;
width: 100%;
max-width: 500px;
background: #fcfcfc;
border-radius: 5px;
}
/* Textos */
.ls-saudacao,
.ls-plataforma {
font-family: "Fira Sans", sans-serif;
text-align: center;
margin-bottom: 16px;
}
.ls-saudacao {
font-weight: 400;
font-size: 40px;
color: #ef7d00;
}
.ls-plataforma {
font-weight: 700;
font-size: 40px;
color: #2d2e83;
}
.ls-subtitle {
font-family: "Open Sans", sans-serif;
font-weight: 700;
font-size: 20px;
color: #ef7d00;
margin-bottom: 10px;
}
.ls-text {
position: static;
width: 87px;
height: 19px;
left: 0px;
top: 37px;
font-family: "Open Sans";
font-style: normal;
font-weight: 700;
font-size: 14px;
line-height: 19px;
/* identical to box height */
color: #848484;
/* Inside auto layout */
flex: none;
order: 1;
flex-grow: 0;
margin: 10px 0px;
}
.is-text {
/* Auto layout */
display: flex;
flex-direction: row;
align-items: flex-start;
padding: 0px;
align-items: center;
position: static;
width: 408px;
height: 48px;
left: 0px;
top: 66px;
/* Inside auto layout */
flex: none;
order: 2;
align-self: stretch;
flex-grow: 0;
margin: 10px 0px;
}
.bs-default {
display: flex;
justify-content: center;
align-items: center;
color: white;
width: 100%;
height: 48px;
background: #2d2e83;
border-radius: 5px;
margin-top: 16px;
}
.ls-forgot-password {
text-align: center;
margin-top: 16px;
}
.ls-link-forgot-password {
text-decoration: underline;
color: #2d2e83;
}
/* Responsividade */
/* Smartphones */
@media (max-width: 575.98px) {
.cs-login {
padding: 40px 20px;
max-width: 300px;
}
.ls-saudacao {
font-size: 24px;
}
.ls-plataforma {
font-size: 20px;
}
.bs-default {
height: 56px;
}
.is-text {
width: 300px;
height: 40px;
}
.ls-forgot-password {
font-size: 12px;
}
.ls-link-forgot-password {
font-size: 12px;
}
}
/* Tablets */
@media (max-width: 991.98px) {
.cs-login {
max-width: 400px;
}
.ls-saudacao {
font-size: 28px;
}
.ls-plataforma {
font-size: 24px;
}
.is-text {
width: 250px;
height: 40px;
}
}
/* Desktops */
@media (min-width: 992px) {
.cs-login {
max-width: 500px;
}
}

View File

@@ -0,0 +1,56 @@
<div class="container-fluid container-login">
<div class="d-flex flex-column">
<div class="row justify-content-center align-items-center" style="height: 100vh;">
<div class="col-12 col-sm-8 col-md-6 col-xl-4">
<div class="cs-login">
<div class="text-center">
<span class="ls-saudacao">Bem-vindo(a),</span>
<span class="ls-plataforma">à plataforma SMART</span>
</div>
<form class="fs-login" [formGroup]="form" (keydown.enter)="submitForm()">
<span class="ls-subtitle">Acesse sua conta</span>
<kendo-formfield>
<label>
<span class="ls-text">Email</span>
<kendo-textbox class="is-text" formControlName="email" placeholder="Informe seu email de acesso" #email
required>
</kendo-textbox>
</label>
<!-- <kendo-formerror *ngIf="form.controls.email.errors?.required">
Erro: Email é obrigatório!
</kendo-formerror>
<kendo-formerror *ngIf="form.controls.email.errors?.email">
Error: Informe um email com formato válido.
</kendo-formerror> -->
</kendo-formfield>
<kendo-formfield>
<label>
<span class="ls-text">Senha</span>
<kendo-textbox class="k-textbox is-text" type="password" placeholder="Informe sua senha" #password
formControlName="password">
<ng-template kendoTextBoxSuffixTemplate>
<button
kendoButton
look="clear"
[icon]="passwordVisible ? 'eye-slash' : 'eye'"
(click)="toggleVisibility()"
type="button"
></button>
</ng-template>
</kendo-textbox>
</label>
<kendo-formerror>Erro: A senha é obrigatória!</kendo-formerror>
</kendo-formfield>
<span class="ls-forgot-password">
Esqueceu a senha? <a class="ls-link-forgot-password">Recupere o acesso</a>
</span>
<button kendoButton class="bs-default" [disabled]="isLoading" [icon]="loadingIcon" (click)="submitForm()">
ENTRAR
</button>
</form>
</div>
</div>
</div>
</div>
</div>
<div kendoDialogContainer></div>

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LoginComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,151 @@
import { AfterViewInit, Component, NgZone, OnInit, ViewChild } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { DialogService } from '@progress/kendo-angular-dialog';
import { TextBoxComponent } from '@progress/kendo-angular-inputs';
import { thumbnailsUpIcon } from '@progress/kendo-svg-icons';
import { ResultApi } from 'src/app/models/result-api.model';
import { MessageFailureComponent } from 'src/app/shared/menssages/message-failure/message-failure.component';
import { AuthService } from '../services/auth.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss',
'./login.component.css']
})
export class LoginComponent implements OnInit, AfterViewInit {
@ViewChild('password') public textbox: TextBoxComponent;
public initialPassword = true;
public passwordVisible = false;
public loadingIcon = '';
public form: FormGroup;
public data: any = {
email: '',
password: '',
};
constructor(private authService: AuthService,
private router: Router,
private dialogService: DialogService,
private ngZone: NgZone
) {
this.form = new FormGroup({
password: new FormControl(this.data.password, [Validators.required, Validators.minLength(3)]),
email: new FormControl(this.data.email, [
Validators.required,
]),
});
}
private dialog: any;
public onEnter(event: KeyboardEvent): void {
event.preventDefault(); // Evita o envio do formulário padrão
if (this.form.valid) {
this.submitForm(); // Apenas submete se o formulário for válido
}
}
public submitForm(): void {
this.form.markAllAsTouched();
if (this.form.valid) {
this.loadingIcon = 'loading';
const domain = '@jurunense.com.br';
let email = this.form.value.email;
// Remover domínio existente se já foi digitado
if (email.toLowerCase().endsWith(domain)) {
email = email.substring(0, email.length - domain.length);
}
const emailUpperCase = (email + domain).toUpperCase();
const passwordUpperCase = this.form.value.password.toUpperCase();
this.authService.login({
email: emailUpperCase,
password: passwordUpperCase
})
.subscribe((res: ResultApi) => {
if (res.success) {
this.loadingIcon = '';
console.log(JSON.stringify(res.data));
this.authService.setDataInLocalStorage('user', JSON.stringify(res.data));
this.authService.setDataInLocalStorage('token', res.data.token);
localStorage.removeItem('cart');
this.router.navigate(['/menu']);
} else {
this.loadingIcon = '';
this.showErrorMessage(res.message);
}
}, err => {
this.loadingIcon = '';
this.showErrorMessage(`${err.error.message}`);
});
}
}
public get isLoading(): boolean {
return this.loadingIcon !== '';
}
public clearForm(): void {
this.form.reset();
}
public togglePass(): void {
const inputEl = this.textbox.input.nativeElement;
if (this.initialPassword) {
inputEl.type = 'password';
this.initialPassword = false;
return;
}
if (inputEl.type === 'password') {
inputEl.type = 'text';
} else {
inputEl.type = 'password';
}
console.log(this.form.controls.password.value);
}
getUserName() {
return this.authService.getUserName();
}
showErrorMessage(message: string) {
console.log('mensagem de erro', message);
const dialogRef = this.dialogService
.open({
title: 'Error',
content: MessageFailureComponent,
actions: [{ text: 'OK', primary: true }],
width: 400,
height: 250,
minWidth: 250,
});
const messageInfo = dialogRef.content.instance;
messageInfo.message = message;
this.ngZone.run(() => {
dialogRef.result.subscribe();
});
}
ngOnInit(): void { }
public ngAfterViewInit(): void {
this.textbox.input.nativeElement.type = 'password';
}
public toggleVisibility(): void {
const inputEl = this.textbox.input.nativeElement;
this.passwordVisible = !this.passwordVisible;
inputEl.type = this.passwordVisible ? 'text' : 'password';
}
}

View File

@@ -0,0 +1,42 @@
<div class="example">
<form class="k-form" [formGroup]="form">
<h5 class="text-center">CADASTRO DE NOVO USUARIO</h5>
<kendo-formfield>
<kendo-label [for]="email" text="Email"></kendo-label>
<kendo-textbox
formControlName="email"
[clearButton]="true"
#email
required
></kendo-textbox>
<kendo-formerror *ngIf="form.controls.email.errors?.required"
>Error: Email is required</kendo-formerror
>
<kendo-formerror *ngIf="form.controls.email.errors?.email"
>Error: Not valid email format</kendo-formerror
>
</kendo-formfield>
<kendo-formfield>
<kendo-label [for]="password" text="Senha"></kendo-label>
<kendo-textbox
formControlName="password"
[clearButton]="true"
#password
required
></kendo-textbox>
<kendo-formerror>Error: Password is required</kendo-formerror>
</kendo-formfield>
<div class="k-form-buttons">
<button class="k-button k-primary" (click)="submitForm()">
Send Reservation Request
</button>
<button class="k-button" (click)="clearForm()">Clear</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,10 @@
.example {
display: flex;
justify-content: center;
align-content: center;
}
.k-form kendo-label:not(:last-of-type) {
flex-direction: column;
margin-bottom: 10px;
}

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RegisterComponent } from './register.component';
describe('RegisterComponent', () => {
let component: RegisterComponent;
let fixture: ComponentFixture<RegisterComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ RegisterComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(RegisterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,60 @@
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { AuthService } from '../services/auth.service';
@Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.scss']
})
export class RegisterComponent implements OnInit {
public form: FormGroup;
public errorMessage: string;
public successMessage: string;
public data: any = {
email: '',
password: '',
};
constructor(private authService: AuthService) {
this.form = new FormGroup({
password: new FormControl(this.data.password, [Validators.required, Validators.minLength(3)]),
email: new FormControl(this.data.email, [
Validators.required,
Validators.email,
]),
});
}
public submitForm(): void {
this.form.markAllAsTouched();
if (this.form.valid){
this.tryRegister({email: this.form.value.email, password: this.form.value.password});
}
}
public clearForm(): void {
this.form.reset();
}
tryRegister(value){
/*this.authService.doRegister(value)
.then(res => {
console.log(res);
this.errorMessage = '';
this.successMessage = 'Your account has been created';
console.log(this.successMessage);
}, err => {
console.log(err);
this.errorMessage = err.message;
this.successMessage = '';
console.log(err.code + ' - ' + this.errorMessage);
});*/
}
ngOnInit(): void {
}
}

View File

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let service: AuthService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AuthService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -0,0 +1,183 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';
import { ResultApi } from 'src/app/models/result-api.model';
import { environment } from 'src/environments/environment';
import { AuthUser } from '../../models/auth.user.model';
import jwt_decode from 'jwt-decode';
import { ModuleSystem } from 'src/app/models/module.model';
import { PagesUser } from 'src/app/models/pages-user.model';
import { ActionsUser } from 'src/app/models/actions-user.model';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private UserAuthenticate = false;
public actionsUser: ActionsUser[];
constructor(public httpClient: HttpClient,
public router: Router) { }
/*doRegister(value){
return new Promise<any>((resolve, reject) => {
this.afAuth.createUserWithEmailAndPassword(value.email, value.password)
.then(res => {
resolve(res);
}, err => reject(err));
});
}
doEmailAndPasswordLogin(value){
return new Promise<any>((resolve, reject) => {
this.afAuth
.signInWithEmailAndPassword(value.email, value.password)
.then(res => {
console.log(res);
resolve(res);
}, err => reject(err));
});
} */
login(value: AuthUser): Observable<ResultApi> {
return this.httpClient.post<ResultApi>(`${environment.url}auth/login`, value);
}
logout() {
localStorage.removeItem('user');
localStorage.removeItem('token');
this.router.navigate(['login']);
}
authenticate(value: AuthUser): Observable<ResultApi> {
return this.httpClient.post<ResultApi>(`${environment.url}auth/authenticate`, value);
}
getDiscount(id: number = 0): Observable<ResultApi> {
const data = localStorage.getItem('user');
const user = JSON.parse(data);
const token = this.getToken();
const headers = new HttpHeaders().set('Authorization', `Basic ${token}`);
let userId = user.id;
if (id > 0){
userId = id;
}
return this.httpClient.get<ResultApi>(`${environment.url}auth/discount-user/${userId}`);
}
getModules(id: number) {
const data = localStorage.getItem('user');
const user = JSON.parse(data);
const token = this.getToken();
const headers = new HttpHeaders().set('Authorization', `Basic ${token}`);
let userId = user.id;
if (id > 0){
userId = id;
}
return this.httpClient.get<ModuleSystem[]>(`${environment.url}access-control/modules/${userId}`);
}
getPagesUser(moduleId: number) {
const data = localStorage.getItem('user');
const user = JSON.parse(data);
const token = this.getToken();
const headers = new HttpHeaders().set('Authorization', `Basic ${token}`);
return this.httpClient.get<PagesUser[]>(`${environment.url}access-control/pages/${user.id}/${moduleId}`);
}
getActionsUser(moduleId: number) {
const data = localStorage.getItem('user');
const user = JSON.parse(data);
const token = this.getToken();
const headers = new HttpHeaders().set('Authorization', `Basic ${token}`);
return this.httpClient.get<ActionsUser[]>(`${environment.url}access-control/actions/${user.id}/${moduleId}`);
}
setDataInLocalStorage(variableName: string, data: any) {
localStorage.setItem(variableName, data);
}
getToken() {
return localStorage.getItem('token');
}
getPayload() {
try {
return jwt_decode(this.getToken()) as any;
} catch (Error) {
return null;
}
}
isManager() {
const data = this.getPayload();
console.log(JSON.stringify(data));
return data.sectorId.toString() === data.sectorManagerId.toString();
}
getUserName() {
const data = localStorage.getItem('user');
const user = JSON.parse(data);
return user.username;
}
getStoreName() {
const data = localStorage.getItem('user');
const user = JSON.parse(data);
return user.name;
}
getUser() {
const data = localStorage.getItem('user');
const user = JSON.parse(data);
return user.id;
}
getSeller() {
const data = localStorage.getItem('user');
const user = JSON.parse(data);
return user.seller;
}
getSupervisor() {
const data = localStorage.getItem('user');
const user = JSON.parse(data);
return user.supervisorId;
}
getStore() {
const data = localStorage.getItem('user');
const user = JSON.parse(data);
return user.store;
}
getDeliveryTime() {
const data = localStorage.getItem('user');
const user = JSON.parse(data);
return user.deliveryTime;
}
deleteDataLocalStorage(variableName: string) {
localStorage.removeItem(variableName);
}
isAuthenticate(){
console.log(localStorage.getItem('token'));
return localStorage.getItem('token') != null;
}
userAction(processId: number, pageId: number, actionId: number) {
const actionUser = this.actionsUser
.find(action => action.moduleId == 2 &&
action.processId == processId &&
action.pageId == pageId &&
action.actionId == actionId &&
action.access == "S" );
console.log(this.actionsUser);
return actionUser !== undefined && actionUser!== null;
}
}

View File

@@ -0,0 +1,25 @@
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HeaderSystemComponent } from './header-system/header-system.component';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { KendoModule } from '../shared/kendo.module';
import { ProductListItemComponent } from './product-list-item/product-list-item.component';
import { ProductModalComponent } from '../sales/components/product-modal/product-modal.component';
import { HeaderAdminComponent } from './header-admin/header-admin.component';
import { HeaderSalesComponent } from './header-sales/header-sales.component';
import { HeaderShoppingComponent } from './header-shopping/header-shopping.component';
@NgModule({
declarations: [HeaderSystemComponent, ProductListItemComponent, HeaderAdminComponent, HeaderSalesComponent, HeaderShoppingComponent, HeaderShoppingComponent],
imports: [
CommonModule,
KendoModule,
ReactiveFormsModule,
FormsModule,
],
exports: [HeaderSystemComponent, ProductListItemComponent, HeaderAdminComponent, HeaderSalesComponent, HeaderShoppingComponent],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
export class ComponentModule { }

View File

@@ -0,0 +1,39 @@
<header class="header-productlist fixed-top">
<div class="container d-flex justify-content-between align-items-center py-3">
<!-- Logo à esquerda -->
<div class="logo-jurunense">
<a href="/#/menu" title="Jurunenese">
<img [src]="imageLogoBase64" alt="Imagem" class="img-fluid" />
</a>
</div>
<!-- Informações do usuário à direita -->
<div class="d-flex align-items-center">
<!-- Dados do usuário -->
<div class="me-3 text-end">
<span class="name-user d-block">{{ userName }}</span>
<span class="last-access d-block">Loja: {{ storeName }}</span>
</div>
<!-- Dropdown de configurações -->
<div class="dropdown">
<a
class="nav-link dropdown-toggle"
href="#"
id="navbarDropdownMenuLink"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<img src="assets/img/config.svg" alt="Configurações" class="img-config" />
</a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownMenuLink">
<li>
<a class="dropdown-item" (click)="logout()">Sair</a>
</li>
</ul>
</div>
</div>
</div>
</header>

View File

@@ -0,0 +1,190 @@
.wrapper {
height: 100vh;
}
.header-productlist {
display: flex;
align-items: center;
padding: 10px 64px;
position: fixed;
width: 100%;
height: 80px;
top: 0;
background: #131d52;
color: #fff;
.logo-jurunense {
img {
max-height: 50px;
width: auto;
}
}
.name-user {
font-family: "Open Sans", sans-serif;
font-weight: 700;
font-size: 14px;
line-height: 19px;
color: #ffffff;
}
.last-access {
font-family: "Open Sans", sans-serif;
font-weight: 400;
font-size: 12px;
line-height: 16px;
color: #848484;
}
.dropdown-toggle {
display: flex;
align-items: center;
background: none;
border: none;
img {
max-height: 24px;
width: auto;
}
}
.dropdown-menu {
background-color: #2d2e83;
border: none;
a {
color: #fff;
text-decoration: none;
&:hover {
color: #ef7d00;
}
}
}
}
/* Footer */
.home-footer {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 46px;
background: #131d52;
.text-footer {
font-family: "Open Sans", sans-serif;
font-size: 10px;
line-height: 14px;
text-align: center;
color: #ffffff;
}
}
/* Buttons */
.new-order {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 40px;
background: #ff9521;
border-radius: 5px;
.text-button {
font-family: "Open Sans", sans-serif;
font-weight: 700;
font-size: 16px;
line-height: 22px;
text-align: center;
color: #ffffff;
}
}
.button-flat {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 40px;
background: #ffffff;
border: 1px solid #ef7d00;
box-sizing: border-box;
border-radius: 5px;
.text-button-flat {
font-family: "Open Sans", sans-serif;
font-weight: 700;
font-size: 16px;
line-height: 22px;
text-align: center;
color: #ef7d00;
}
}
.button-flat-blue {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 40px;
background: #ffffff;
border: 1px solid #2d2e83;
box-sizing: border-box;
border-radius: 5px;
.text-button-flat-blue {
font-family: "Open Sans", sans-serif;
font-weight: 700;
font-size: 16px;
line-height: 22px;
text-align: center;
color: #2d2e83;
}
}
/* Responsividade */
/* Smartphones */
@media (max-width: 575.98px) {
.header-productlist {
padding: 10px;
.logo-jurunense img {
max-width: 120px;
}
.name-user {
font-size: 12px;
}
.last-access {
font-size: 10px;
}
}
.new-order .text-button,
.button-flat .text-button-flat,
.button-flat-blue .text-button-flat-blue {
font-size: 14px;
}
}
/* Tablets */
@media (max-width: 991.98px) {
.header-productlist {
padding: 10px 20px;
.logo-jurunense img {
max-width: 150px;
}
}
}
/* Desktops */
@media (min-width: 992px) {
.logo-jurunense img {
max-width: 170px;
}
}

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HeaderAdminComponent } from './header-admin.component';
describe('HeaderAdminComponent', () => {
let component: HeaderAdminComponent;
let fixture: ComponentFixture<HeaderAdminComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HeaderAdminComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HeaderAdminComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,42 @@
<header class="header-productlist fixed-top">
<div class="container d-flex justify-content-between align-items-center py-3">
<!-- Logo -->
<div class="logo-jurunense">
<a href="/#/menu" title="Jurunense">
<img [src]="imageLogoBase64" alt="Logo Jurunense" class="img-fluid" />
</a>
</div>
<!-- Informações do usuário -->
<div class="user-info d-flex align-items-center">
<!-- Nome do usuário e loja -->
<div class="user-details me-3 text-end">
<span class="name-user d-block">{{ userName }}</span>
<span class="last-access d-block">Loja: {{ storeName }}</span>
</div>
<!-- Carrinho -->
<div class="cart me-3 text-center">
<kendo-badge-container>
<img src="assets/img/cart.svg" alt="Carrinho" class="cart-icon" data-bs-toggle="offcanvas"
data-bs-target="#offcanvasRight" aria-controls="offcanvasRight" />
<kendo-badge [align]="align" [position]="position" [themeColor]="themeBadge">{{ (shoppingItems$ |
async)?.length || 0 }}</kendo-badge>
</kendo-badge-container>
</div>
<!-- Dropdown de configurações -->
<div class="dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button"
data-bs-toggle="dropdown" aria-expanded="false">
<img src="assets/img/config.svg" alt="Configurações" class="img-config" />
</a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownMenuLink">
<li>
<a class="dropdown-item" (click)="logout()">Sair</a>
</li>
</ul>
</div>
</div>
</div>
</header>

View File

@@ -0,0 +1,85 @@
.header-productlist {
display: flex;
align-items: center;
padding: 10px 64px;
position: fixed;
width: 100%;
height: 80px;
top: 0;
background: #131d52;
color: #ffffff;
z-index: 1000;
.logo-jurunense img {
max-height: 50px;
width: auto;
}
.user-info {
display: flex;
align-items: center;
.user-details {
text-align: right;
.name-user {
font-family: "Open Sans", sans-serif;
font-weight: 700;
font-size: 14px;
line-height: 19px;
color: #ffffff;
}
.last-access {
font-family: "Open Sans", sans-serif;
font-weight: 400;
font-size: 12px;
line-height: 16px;
color: #848484;
}
}
.cart {
position: relative;
.cart-icon {
max-height: 24px;
width: auto;
cursor: pointer;
}
kendo-badge {
position: absolute;
top: -13px;
right: -13px;
font-size: 14px;
font-weight: 400;
}
}
.dropdown-toggle {
background: none;
border: none;
img {
max-height: 24px;
width: auto;
}
}
.dropdown-menu {
background-color: #2d2e83;
border: none;
a {
color: #ffffff;
text-decoration: none;
&:hover {
color: #ef7d00;
}
}
}
}
}

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HeaderSalesComponent } from './header-sales.component';
describe('HeaderSalesComponent', () => {
let component: HeaderSalesComponent;
let fixture: ComponentFixture<HeaderSalesComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HeaderSalesComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HeaderSalesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,205 @@
<header class="header-productlist fixed-top">
<div class="container">
<div class="row g-0 align-items-center">
<!-- Logo and Menu -->
<div class="col-6 col-md-2 d-flex align-items-center logo-jurunense">
<div class="btn-menu">
<button class="menu-toggle me-3 d-flex align-items-center" (click)="openMenu()">
<img src="assets/img/menu.svg" alt="Menu" width="24" height="24" />
</button>
</div>
<div class="logo-jurunense">
<a href="/#/sales/home" title="Jurunenese">
<img [src]="imageLogoBase64" alt="Imagem" class="img-fluid" />
</a>
</div>
</div>
<!-- Search Section para desktops -->
<div class="col-md-8 px-5 d-none d-md-flex">
<kendo-textbox class="search-product-desktop" [formControl]="searchProduct"
placeholder="Pesquise o produto desejado por aqui" (keydown.enter)="onSearch()">
<ng-template kendoTextBoxSuffixTemplate>
<button kendoButton fillMode="clear" icon="search" (click)="onSearch()"></button>
</ng-template>
</kendo-textbox>
</div>
<!-- User Info and Cart -->
<div class="col-6 col-md-2 d-flex justify-content-end align-items-center">
<!-- Carrinho -->
<div class="d-flex align-items-center">
<kendo-badge-container>
<img src="assets/img/cart.svg" alt="Carrinho" data-bs-toggle="offcanvas"
data-bs-target="#offcanvasRight" aria-controls="offcanvasRight" />
<kendo-badge [align]="align" [position]="position" [themeColor]="themeBadge">
{{ (shopping$ | async).length }}
</kendo-badge>
</kendo-badge-container>
</div>
<!-- Avatar com dropdown para dispositivos móveis -->
<!-- <div class="info-user">
<div class="dropdown ms-3">
<button class="btn dropdown-toggle p-0" id="userMenuDropdown" type="button"
data-bs-toggle="dropdown" aria-expanded="false">
<kendo-avatar [imageSrc]="'https://i.pravatar.cc/150?img=7'" [size]="'medium'"
[shape]="'circle'" title="{{ userName }}"></kendo-avatar>
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userMenuDropdown">
<li class="dropdown-header">
<span class="username"><strong>{{ userName }}</strong></span>
<div class="text-muted"><span class="loja">Loja: {{ storeName }}</span></div>
</li>
<hr>
<li><a class="dropdown-item" href="/#/profile">Perfil</a></li>
<li><a class="dropdown-item" href="/#/settings">Configurações</a></li>
<li><a class="dropdown-item" (click)="logout()">Sair</a></li>
</ul>
</div>
</div> -->
<!-- Nome do usuário e loja -->
<div class="user-details me-3 text-end">
<span class="name-user d-block">{{ userName }}</span>
<span class="last-access d-block">Loja: {{ storeName }}</span>
</div>
<!-- Dropdown de configurações -->
<div class="dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button"
data-bs-toggle="dropdown" aria-expanded="false">
<img src="assets/img/config.svg" alt="Configurações" class="img-config" />
</a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownMenuLink">
<li>
<a class="dropdown-item" (click)="logout()">Sair</a>
</li>
</ul>
</div>
</div>
<!-- Search Section para dispositivos móveis e tablets -->
<div class="col-12 mt-3">
<kendo-textbox class="search-product" [formControl]="searchProduct"
placeholder="Pesquise o produto desejado por aqui" (keydown.enter)="onSearch()">
<ng-template kendoTextBoxSuffixTemplate>
<button kendoButton fillMode="clear" icon="search" (click)="onSearch()"></button>
</ng-template>
</kendo-textbox>
</div>
</div>
</div>
<!-- Modal de Menu -->
<div class="menu-modal" [ngClass]="{'open': isMenuOpen, 'close': !isMenuOpen}">
<div class="menu-content">
<!-- Cabeçalho do Modal -->
<div class="menu-header">
<div class="user-info">
<img src="https://via.placeholder.com/64" alt="Avatar" class="user-avatar" />
<div class="user-text">
<span class="bold-text">{{ userName }}</span>
<span class="subtitle">Loja: {{ storeName }}</span>
</div>
</div>
<button class="close-btn" (click)="closeMenu()">×</button>
</div>
<!-- Botões de Entrar e Cadastrar -->
<div class="menu-buttons">
<button class="btn-enter" (click)="logout()">Sair</button>
<button class="btn-register" (click)="closeMenu()">Voltar</button>
</div>
<!-- Lista de Links -->
<ul class="menu-links">
<!-- <li>
<a href="#">Nossas lojas</a>
<i class="fa-solid fa-chevron-right icon"></i>
</li>
<hr /> -->
<li>
<a href="/#/product-list" (click)="applyFilter({ urlCategory: [] })"><strong>Todos os
departamentos</strong></a>
<i class="fa-solid fa-chevron-right icon"></i>
</li>
<hr />
<!-- Lista Dinâmica -->
<li *ngFor="let department of departments">
<a href="/#/product-list" (click)="applyFilter({ urlCategory: department.path })">{{ department.text
}}</a>
<i class="fa-solid fa-chevron-right icon"></i>
</li>
</ul>
<!-- Filtros Adicionais -->
<div class="menu-filters">
<legend class="k-form-legend mt-3">Marcas</legend>
<div *ngIf="brands && brands.length > 0">
<kendo-treeview kendoTreeViewHierarchyBinding [nodes]="brands" textField="text"
[kendoTreeViewCheckable]="{ mode: 'multiple' }" [(checkedKeys)]="selectedBrandKeys"
(checkedChange)="applyFilter({ brands: selectedBrandKeys })">
</kendo-treeview>
</div>
<!-- Filtros Gerais -->
<div class="filters-section">
<legend class="k-form-legend mt-3">Filtros</legend>
<label class="k-label d-block">
<input type="checkbox" kendoCheckBox [(ngModel)]="onlyWithStock" />
<span class="ms-2">Somente produtos com estoque</span>
</label>
<label class="k-label d-block mt-2">
<span>Filial de estoque</span>
<kendo-combobox [data]="store$ | async" textField="id" valueField="id"
(selectionChange)="selectedStore($event)">
</kendo-combobox>
</label>
<label class="k-label d-block mt-2">
<input type="checkbox" kendoCheckBox [(ngModel)]="productPromotion" />
<span class="ms-2">Produtos em promoção</span>
</label>
<label class="k-label d-block mt-2">
<span>Faixa de desconto</span>
<kendo-rangeslider [(ngModel)]="percentOff" [min]="minPercentOff" [max]="maxPercentOff"
[smallStep]="smallStep" [largeStep]="largeStep">
</kendo-rangeslider>
</label>
<label class="k-label d-block mt-2">
<input type="checkbox" kendoCheckBox [(ngModel)]="markdown" />
<span class="ms-2">Produtos que baixaram de preço</span>
</label>
<label class="k-label d-block mt-2">
<input type="checkbox" kendoCheckBox [(ngModel)]="oportunity" />
<span class="ms-2">Oportunidades</span>
</label>
<label class="k-label d-block mt-2">
<input type="checkbox" kendoCheckBox [(ngModel)]="offers" />
<span class="ms-2">Ofertas imperdíveis</span>
</label>
<!-- Botão de Aplicar -->
<div class="apply-filters mt-4">
<button kendoButton class="w-100" (click)="getFilterProducts()">
Aplicar Filtros
</button>
</div>
</div>
</div>
</div>
</div>
</header>

View File

@@ -0,0 +1,490 @@
.header-productlist {
display: flex;
align-items: center;
padding: 10px 16px;
position: fixed;
width: 100%;
height: auto;
top: 0;
background: #131d52;
color: #ffffff;
z-index: 1000;
.menu-toggle {
background: none;
border: none;
cursor: pointer;
}
.search-product {
width: 100%;
height: 40px;
border-radius: 5px;
padding: 0 10px;
background-color: #ffffff;
color: #333;
}
.name-user {
font-size: 12px;
font-weight: bold;
color: #ffffff;
}
kendo-badge {
position: absolute;
top: -11px;
right: -11px;
font-size: 14px;
font-weight: 400;
}
.last-access {
font-size: 10px;
color: #848484;
}
.center {
display: flex;
justify-content: center;
align-items: center;
}
.dropdown-content {
position: absolute;
background: #ffffff;
border: 1px solid #ccc;
padding: 10px;
z-index: 1000;
}
.dropdown-menu {
background-color: #2d2e83;
border: none;
.dropdown-item {
color: #ffffff;
&:hover {
color: #ef7d00;
}
}
}
.btn-menu {
padding: 1px;
display: flex;
border: none;
background-color: transparent;
width: 24px;
height: 24px;
margin-right: 30px;
}
.username {
font-size: 12px;
color: #fff;
}
.loja {
font-size: 11px;
color: #f4f4f4;
}
}
/* Modal Fullscreen */
.menu-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #fff;
z-index: 1050;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
transform: translateX(-100%);
transition: transform 0.5s ease;
}
/* Classe para abrir o modal */
.menu-modal.open {
transform: translateX(0);
}
/* Classe para fechar o modal */
.menu-modal.close {
transform: translateX(-100%);
}
/* Conteúdo do Menu */
.menu-content {
width: 100%;
height: 100%;
padding: 20px;
overflow-y: auto;
display: flex;
flex-direction: column;
color: #333;
}
/* Cabeçalho do Menu */
.menu-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.user-info {
display: flex;
align-items: center;
}
.user-avatar {
width: 64px;
height: 64px;
border-radius: 50%;
margin-right: 10px;
}
.user-text {
display: flex;
flex-direction: column;
font-size: 14px;
}
.bold-text {
font-weight: bold;
}
.subtitle {
color: #666;
}
/* Botões: Entrar e Cadastrar */
.menu-buttons {
display: flex;
/* Flexbox para alinhar os botões */
justify-content: space-between;
/* Espaço entre os botões */
gap: 10px;
/* Espaçamento entre os botões */
width: 100%;
/* Ocupa 100% da largura */
margin: 10px 0;
/* Espaçamento acima e abaixo */
}
.btn-enter,
.btn-register {
flex: 1;
/* Cada botão ocupa a mesma largura */
padding: 10px 0;
/* Espaçamento interno vertical */
text-align: center;
/* Alinhamento do texto */
font-size: 16px;
/* Tamanho da fonte */
font-weight: bold;
cursor: pointer;
border-radius: 5px;
}
.btn-enter {
background-color: #131d52;
color: #fff;
border: none;
}
.btn-register {
background: transparent;
color: #131d52;
border: 2px solid #131d52;
}
.btn-enter:hover,
.btn-register:hover {
opacity: 0.9;
/* Efeito ao passar o mouse */
}
/* Lista de Links */
.menu-links {
list-style: none;
padding: 0;
margin-top: 20px;
}
.menu-item {
// flex-direction: row;
flex: 1;
justify-content: space-between;
}
.menu-links li {
display: flex;
justify-content: space-between;
/* Texto à esquerda, ícone à direita */
align-items: center;
padding: 15px 20px;
border-bottom: 1px solid #f1f1f1;
transition: background-color 0.3s ease;
cursor: pointer;
}
.menu-links li:hover {
background-color: #f5f5f5;
/* Cor ao passar o mouse */
}
.menu-links a {
text-decoration: none;
/* Remove sublinhado */
color: #333;
font-size: 16px;
font-weight: 400;
flex-grow: 1;
/* Garante que o texto use o espaço restante */
}
.menu-links a:hover {
color: #131d52;
/* Cor principal ao hover */
}
.menu-links .icon {
font-size: 14px;
color: #999;
/* Cor do ícone */
transition: transform 0.3s ease, color 0.3s ease;
}
.menu-links li:hover .icon {
color: #131d52;
/* Cor ao hover */
transform: translateX(5px);
/* Desliza o ícone para direita */
}
hr {
border: 0;
border-top: 1px solid #ddd;
margin: 10px 0;
}
/* Botão de Fechar */
.close-btn {
font-size: 24px;
background: none;
border: none;
cursor: pointer;
color: #333;
}
/* Smartphones */
@media (max-width: 575.98px) {
.header-productlist {
flex-wrap: wrap;
.menu-toggle {
display: block;
}
.logo-jurunense img {
max-width: 120px;
}
.search-product {
margin-top: 5px;
margin-bottom: 10px;
order: 2;
}
.search-product-desktop {
display: none;
}
.name-user,
.last-access {
display: none;
}
.info-user-desktop {
display: none;
}
.info-user {
display: block;
}
}
.menu-content {
padding: 10px;
/* Reduz o padding */
font-size: 12px;
/* Fonte geral menor */
}
.k-form-legend {
font-size: 12px;
/* Tamanho menor para legendas */
}
.menu-buttons {
flex-direction: column;
gap: 5px;
}
.btn-enter,
.btn-register {
font-size: 12px;
padding: 6px;
}
/* Lista de marcas */
.kendo-treeview {
max-height: 200px;
/* Reduz altura */
overflow-y: auto;
}
/* Inputs e checkboxes menores */
label.k-label {
font-size: 10px;
display: flex;
align-items: center;
margin-bottom: 5px;
}
input[type="checkbox"] {
transform: scale(0.8);
/* Menor */
margin-right: 5px;
}
kendo-combobox,
kendo-rangeslider {
width: 100%;
transform: scale(0.85);
/* Reduz tamanho */
}
kendo-rangeslider {
margin-top: 5px;
}
/* Ajusta espaçamento das legendas */
legend {
margin-bottom: 8px;
}
/* Botão de aplicar filtros */
button[kendoButton] {
width: 100%;
font-size: 12px;
padding: 8px;
}
.dropdown-toggle {
display: none;
}
.dropdown-menu {
display: none;
}
}
/* Tablets */
@media (max-width: 991.98px) {
.header-productlist {
flex-wrap: wrap;
.menu-toggle {
display: block;
}
.logo-jurunense img {
max-width: 150px;
}
.search-product {
margin-top: 5px;
margin-bottom: 10px;
order: 2;
}
.search-product-desktop {
display: none;
}
.name-user,
.last-access {
display: none;
}
.info-user-desktop {
display: none;
}
.info-user {
display: block;
}
}
.dropdown-toggle,
.user-details {
display: none;
}
.dropdown-menu,
.user-details {
display: none;
}
}
/* Desktops */
@media (min-width: 992px) {
.header-productlist {
flex-wrap: nowrap;
.menu-toggle {
display: none;
}
.logo-jurunense img {
max-width: 170px;
}
.search-product {
margin: 0 auto;
margin-bottom: 0;
order: 0;
}
.search-product {
display: none;
}
.btn-menu {
display: none;
}
.info-user {
display: none;
}
.name-user,
.last-access {
display: block;
}
}
}

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HeaderShoppingComponent } from './header-shopping.component';
describe('HeaderShoppingComponent', () => {
let component: HeaderShoppingComponent;
let fixture: ComponentFixture<HeaderShoppingComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HeaderShoppingComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HeaderShoppingComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,48 @@
<header class="header-productlist fixed-top">
<div class="container d-flex justify-content-between align-items-center py-3">
<!-- Logo à esquerda -->
<div class="logo-jurunense">
<a href="/" title="Jurunenese">
<img [src]="imageLogoBase64" alt="Imagem" class="img-fluid" />
</a>
</div>
<!-- Informações do usuário à direita -->
<div class="d-flex align-items-center">
<!-- Carrinho -->
<div class="d-flex align-items-center">
<kendo-badge-container>
<img src="assets/img/cart.svg" alt="Carrinho" data-bs-toggle="offcanvas"
data-bs-target="#offcanvasRight" aria-controls="offcanvasRight" />
<kendo-badge [align]="align" [position]="position" [themeColor]="themeBadge">
{{ (shopping$ | async).length }}
</kendo-badge>
</kendo-badge-container>
</div>
<!-- Dados do usuário -->
<div class="me-3 text-end">
<span class="name-user d-block">{{ userName }}</span>
<span class="last-access d-block">Loja: {{ storeName }}</span>
</div>
<!-- Dropdown de configurações -->
<div class="dropdown">
<a
class="nav-link dropdown-toggle"
href="#"
id="navbarDropdownMenuLink"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<img src="assets/img/config.svg" alt="Configurações" class="img-config" />
</a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownMenuLink">
<li>
<a class="dropdown-item" (click)="logout()">Sair</a>
</li>
</ul>
</div>
</div>
</div>
</header>

View File

@@ -0,0 +1,197 @@
.wrapper {
height: 100vh;
}
.header-productlist {
display: flex;
align-items: center;
padding: 10px 64px;
position: fixed;
width: 100%;
height: 80px;
top: 0;
background: #131d52;
color: #fff;
.logo-jurunense {
img {
max-height: 50px;
width: auto;
}
}
.name-user {
font-family: "Open Sans", sans-serif;
font-weight: 700;
font-size: 14px;
line-height: 19px;
color: #ffffff;
}
.last-access {
font-family: "Open Sans", sans-serif;
font-weight: 400;
font-size: 12px;
line-height: 16px;
color: #848484;
}
.dropdown-toggle {
display: flex;
align-items: center;
background: none;
border: none;
img {
max-height: 24px;
width: auto;
}
}
.dropdown-menu {
background-color: #2d2e83;
border: none;
a {
color: #fff;
text-decoration: none;
&:hover {
color: #ef7d00;
}
}
}
}
/* Footer */
.home-footer {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 46px;
background: #131d52;
.text-footer {
font-family: "Open Sans", sans-serif;
font-size: 10px;
line-height: 14px;
text-align: center;
color: #ffffff;
}
}
/* Buttons */
.new-order {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 40px;
background: #ff9521;
border-radius: 5px;
.text-button {
font-family: "Open Sans", sans-serif;
font-weight: 700;
font-size: 16px;
line-height: 22px;
text-align: center;
color: #ffffff;
}
}
.button-flat {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 40px;
background: #ffffff;
border: 1px solid #ef7d00;
box-sizing: border-box;
border-radius: 5px;
.text-button-flat {
font-family: "Open Sans", sans-serif;
font-weight: 700;
font-size: 16px;
line-height: 22px;
text-align: center;
color: #ef7d00;
}
}
.button-flat-blue {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 40px;
background: #ffffff;
border: 1px solid #2d2e83;
box-sizing: border-box;
border-radius: 5px;
.text-button-flat-blue {
font-family: "Open Sans", sans-serif;
font-weight: 700;
font-size: 16px;
line-height: 22px;
text-align: center;
color: #2d2e83;
}
}
/* Responsividade */
/* Smartphones */
@media (max-width: 575.98px) {
.header-productlist {
padding: 10px;
.logo-jurunense img {
max-width: 120px;
}
.name-user {
font-size: 12px;
}
.last-access {
font-size: 10px;
}
}
.new-order .text-button,
.button-flat .text-button-flat,
.button-flat-blue .text-button-flat-blue {
font-size: 14px;
}
}
kendo-badge {
position: absolute;
top: -11px;
right: -11px;
font-size: 14px;
font-weight: 400;
}
/* Tablets */
@media (max-width: 991.98px) {
.header-productlist {
padding: 10px 20px;
.logo-jurunense img {
max-width: 150px;
}
}
}
/* Desktops */
@media (min-width: 992px) {
.logo-jurunense img {
max-width: 170px;
}
}

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HeaderSystemComponent } from './header-system.component';
describe('HeaderSystemComponent', () => {
let component: HeaderSystemComponent;
let fixture: ComponentFixture<HeaderSystemComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HeaderSystemComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HeaderSystemComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,9 @@
<div class="product">
<div class="description">
<div class="product-name">{{ product.description }}</div>
<div class="category-name">{{ product.category }}</div>
</div>
<div class="price">
<div>{{ product.salePrice | currency }}</div>
</div>
</div>

View File

@@ -0,0 +1,27 @@
.product {
width: 100%;
display: flex;
align-items: center;
border-bottom-width: 1px;
border-bottom-color: #ebebeb;
border-bottom-style: solid;
z-index: 9999;
}
.description {
flex: 1;
z-index: 9999;
}
.category-name {
font-size: 12px;
}
.product-name {
font-size: 16px;
}
.product-name,
.price {
height: auto;
font-weight: bold;
}
.product {
padding: 12px;
}

View File

@@ -0,0 +1,28 @@
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { ProductListItemComponent } from './product-list-item.component';
describe('ProductListItemComponent', () => {
let component: ProductListItemComponent;
let fixture: ComponentFixture<ProductListItemComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ProductListItemComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProductListItemComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,16 @@
import { Component, Input, OnInit } from '@angular/core';
import { SaleProduct } from 'src/app/models/sale-product.model';
@Component({
selector: 'app-product-list-item',
templateUrl: './product-list-item.component.html',
styleUrls: ['./product-list-item.component.scss']
})
export class ProductListItemComponent implements OnInit {
@Input() public product: SaleProduct;
constructor() { }
ngOnInit() {
}
}

View File

@@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { CustomerComponent } from './customer/customer.component';
import { EditCustomerComponent } from './edit-customer/edit-customer.component';
import { MenuCrmComponent } from './menu-crm/menu-crm.component';
const routes: Routes = [
{
path: '', component: MenuCrmComponent,
children: [
{ path: 'customer', component: CustomerComponent },
{ path: 'customer/edit', component: EditCustomerComponent },
]
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class CrmRoutingModule { }

23
src/app/crm/crm.module.ts Normal file
View File

@@ -0,0 +1,23 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CrmRoutingModule } from './crm-routing.module';
import { MenuCrmComponent } from './menu-crm/menu-crm.component';
import { ComponentModule } from '../components/component.module';
import { CustomerComponent } from './customer/customer.component';
import { KendoModule } from '../shared/kendo.module';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { EditCustomerComponent } from './edit-customer/edit-customer.component';
@NgModule({
declarations: [MenuCrmComponent, CustomerComponent, EditCustomerComponent],
imports: [
CommonModule,
CrmRoutingModule,
ComponentModule,
FormsModule,
ReactiveFormsModule,
KendoModule,
]
})
export class CrmModule { }

View File

@@ -0,0 +1,94 @@
<div class="container mt-3 my-5">
<div>
<span class="title">Lista de clientes</span>
</div>
<div class="mt-2 w-100" class="border-radius: 20px;">
<form [formGroup]="searchForm">
<kendo-textbox
class="w-100 border"
placeholder="Informe os dados para localizar os clientes"
type="text"
formControlName="textSearch"
(keydown)="searchCustomer($event)"
>
<ng-template kendoTextBoxPrefixTemplate>
<kendo-icon name="search"></kendo-icon>
</ng-template>
<ng-template kendoTextBoxSuffixTemplate>
<div class="example-wrapper">
<kendo-combobox
[data]="listItems"
style="width: 250px"
formControlName="search"
>
</kendo-combobox>
</div>
</ng-template>
</kendo-textbox>
</form>
</div>
<div class="mt-2">
<ng-container>
<kendo-grid
style="height: calc(100vh - 280px)"
[data]="customer$ | async"
[pageSize]="20"
[pageable]="true"
[sortable]="true"
[reorderable]="true"
[resizable]="true"
[columnMenu]="{ filter: true }"
>
<kendo-grid-column field="customerId" title="Código" [width]="30">
<ng-template kendoGridCellTemplate let-dataItem>
<div>{{ dataItem.customerId }}</div>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="name" title="Nome" [width]="150">
<ng-template kendoGridCellTemplate let-dataItem>
<div>{{ dataItem.name }}</div>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="cpfcnpj" title="CPF / CNPJ" [width]="60">
<ng-template kendoGridCellTemplate let-dataItem>
<div>{{ dataItem.cpfCnpj }}</div>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="phone" title="Telefone" [width]="60">
<ng-template kendoGridCellTemplate let-dataItem>
<div>{{ dataItem.phone }}</div>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="cellPhone" title="Celular" [width]="60">
<ng-template kendoGridCellTemplate let-dataItem>
<div>{{ dataItem.cellPhone }}</div>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="cellPhone" title="Ações" [width]="50">
<ng-template kendoGridCellTemplate let-dataItem>
<div>
<a href="/crm/customer/edit">
<kendo-avatar shape="circle" initials="">
<kendo-icon name="edit"></kendo-icon>
</kendo-avatar>
</a>
</div>
</ng-template>
</kendo-grid-column>
</kendo-grid>
</ng-container>
<kendo-floatingactionbutton
icon="add"
text="Novo cliente"
[align]="{ horizontal: 'end', vertical: 'bottom' }"
positionMode="absolute"
>
</kendo-floatingactionbutton>
</div>
</div>

View File

@@ -0,0 +1,13 @@
.title {
width: 810px;
height: 49px;
font-family: Montserrat;
font-style: normal;
font-weight: 300;
font-size: 40px;
line-height: 49px;
color: rgba(107, 110, 190, 1);
;
}

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CustomerComponent } from './customer.component';
describe('CustomerComponent', () => {
let component: CustomerComponent;
let fixture: ComponentFixture<CustomerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CustomerComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CustomerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,55 @@
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { FabAlign } from '@progress/kendo-angular-buttons';
import { Observable } from 'rxjs';
import { Customer } from 'src/app/models/customer.model';
import { CustomerService } from 'src/app/services/customer.service';
@Component({
selector: 'app-customer',
templateUrl: './customer.component.html',
styleUrls: ['./customer.component.scss']
})
export class CustomerComponent implements OnInit {
public listItems: Array<string> = [
'Nome',
'CPF',
'Telefone',
'Celular'
];
public listFields: Array<string> = [
'name',
'document',
'phone',
'cellPhone'
];
public topEnd: FabAlign = { vertical: 'top', horizontal: 'end' };
customer$: Observable<Customer[]>;
public errorObject = null;
public isloading = false;
public searchForm: FormGroup;
constructor(private customerService: CustomerService) {
this.searchForm = new FormGroup({
search: new FormControl(),
textSearch: new FormControl(),
});
}
ngOnInit(): void {
}
searchCustomer(event){
if (event.keyCode === 13) {
console.log(this.searchForm.value);
const indice = this.listItems.indexOf(this.searchForm.get('search').value);
const field = this.listFields[indice];
const textSearh = this.searchForm.get('textSearch').value;
this.customer$ = this.customerService.getCustomerByQuery(field, textSearh);
// const filter: FilterProduct = { brands: [], text: this.searchProduct.value };
// this.getSaleProducts(filter);
}
}
}

View File

@@ -0,0 +1,200 @@
<div class="container">
<form
class="k-form m-3 p-3"
style="background-color: white"
[formGroup]="form"
>
<fieldset class="k-form-fieldset">
<legend class="k-form-legend">Cadastro de cliente</legend>
<div class="col-12 col-sm-12 col-md-8">
<div class="row">
<div class="col-12 col-sm-6 col-md-6">
<kendo-formfield>
<kendo-label [for]="cpf" text="CPF / CNPJ"></kendo-label>
<kendo-textbox
formControlName="username"
#cpf
required
></kendo-textbox>
<kendo-formerror
>Error: Número do CPF é obrigatório</kendo-formerror
>
</kendo-formfield>
</div>
<div class="ccol-12 col-sm-6 col-md-6">
<kendo-formfield>
<kendo-label [for]="ie" text="Insc Estadual"></kendo-label>
<kendo-textbox formControlName="numberState" #ie></kendo-textbox>
</kendo-formfield>
</div>
</div>
</div>
<div class="col-12 col-sm-12 col-md-6">
<kendo-formfield>
<kendo-label [for]="name" text="Nome"></kendo-label>
<kendo-textbox
formControlName="name"
[clearButton]="true"
#name
required
></kendo-textbox>
<kendo-formerror
>Error: O nome do cliente é obrigatório</kendo-formerror
>
</kendo-formfield>
</div>
<div class="col-6 col-sm-6 col-md-6">
<kendo-formfield>
<kendo-label [for]="phone" text="Telefone"></kendo-label>
<kendo-textbox formControlName="cellPhone" #phone></kendo-textbox>
</kendo-formfield>
<kendo-formfield>
<div class="k-form-field-checkbox-wrap">
<input
kendoCheckBox
id="whatsapp1"
type="checkbox"
formControlName="whatsapp"
/>
<kendo-label
class="k-checkbox-label"
for="whatsapp1"
text="Telefone cadastrado no whatsapp?"
></kendo-label>
</div>
</kendo-formfield>
</div>
<div class="col-12 col-sm-12 col-md-8">
<kendo-formfield>
<kendo-label [for]="email" text="E-Mail"></kendo-label>
<kendo-textbox
formControlName="email"
[clearButton]="true"
#email
required
></kendo-textbox>
<kendo-formerror>Error: Informe um email do cliente</kendo-formerror>
</kendo-formfield>
</div>
<legend class="k-form-legend mt-5">Endereço</legend>
<div class="col-6 col-sm-3 col-md-2">
<kendo-formfield>
<kendo-label [for]="zipcode" text="CEP"></kendo-label>
<kendo-textbox
formControlName="cep"
#zipcode
required
></kendo-textbox>
<kendo-formerror
>Error: Informe um CEP para o endereço do cliente</kendo-formerror
>
</kendo-formfield>
</div>
<div class="col-12">
<div class="row">
<div class="col-8">
<kendo-formfield>
<kendo-label [for]="address" text="Endereço"></kendo-label>
<kendo-textbox
formControlName="address"
#address
required
></kendo-textbox>
<kendo-formerror
>Error: Informe o endereço do cliente</kendo-formerror
>
</kendo-formfield>
</div>
<div class="col-4">
<kendo-formfield>
<kendo-label [for]="number" text="Número"></kendo-label>
<kendo-textbox
formControlName="addressNumber"
#number
required
></kendo-textbox>
<kendo-formerror
>Error: Informe o número do endereço do cliente</kendo-formerror
>
</kendo-formfield>
</div>
</div>
</div>
<div class="col-12">
<div class="row">
<div class="col-8">
<kendo-formfield>
<kendo-label [for]="neighborhood" text="Bairro"></kendo-label>
<kendo-textbox
formControlName="neighborhood"
#neighborhood
required
></kendo-textbox>
<kendo-formerror
>Error: Informe o bairro do endereço</kendo-formerror
>
</kendo-formfield>
</div>
<div class="col-4">
<kendo-formfield>
<kendo-label [for]="complement" text="Complemento"></kendo-label>
<kendo-textbox
formControlName="complement"
#complement
></kendo-textbox>
</kendo-formfield>
</div>
</div>
</div>
<div class="col-12">
<div class="row">
<div class="col-8">
<kendo-formfield>
<kendo-label [for]="city" text="Cidade"></kendo-label>
<kendo-textbox
formControlName="city"
#city
></kendo-textbox>
<kendo-formerror
>Error: Informe a cidade do endereço</kendo-formerror
>
</kendo-formfield>
</div>
<div class="col-2">
<kendo-formfield>
<kendo-label [for]="state" text="Estado"></kendo-label>
<kendo-textbox
formControlName="state"
#state
></kendo-textbox>
</kendo-formfield>
</div>
</div>
</div>
<kendo-formfield>
<div class="k-form-field-checkbox-wrap">
<input
kendoCheckBox
id="notications"
type="checkbox"
formControlName="notifications"
/>
<kendo-label
class="k-checkbox-label"
for="notications"
text="Deseja participar do programa de fidelidade?"
></kendo-label>
</div>
</kendo-formfield>
</fieldset>
</form>
</div>

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { EditCustomerComponent } from './edit-customer.component';
describe('EditCustomerComponent', () => {
let component: EditCustomerComponent;
let fixture: ComponentFixture<EditCustomerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ EditCustomerComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EditCustomerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,196 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { DialogService } from '@progress/kendo-angular-dialog';
import { EMPTY, throwError } from 'rxjs';
import { catchError, map, switchMap, take, tap } from 'rxjs/operators';
import { Customer } from 'src/app/models/customer.model';
import { CustomerService } from 'src/app/services/customer.service';
import { MessageService } from 'src/app/services/messages.service';
import { ConsultaCepService } from 'src/app/shared/services/consulta-cep.service';
@Component({
selector: 'app-edit-customer',
templateUrl: './edit-customer.component.html',
styleUrls: ['./edit-customer.component.scss']
})
export class EditCustomerComponent implements OnInit {
public phoneNumberValue = '';
public phoneNumberMask = '(99) 00000-0000';
public cpfMask = '000.000.000-00';
public cnpjMask = '00.000.000/0000-00';
public customer: Customer;
public isloading = false;
public errorObject: any;
public result;
loaderVisible = false;
@ViewChild('formCustomer') formCustomer: ElementRef;
@ViewChild('inputCpf') inputCpf: ElementRef;
public form: FormGroup;
public customerData: any = {
company: false,
cpfCnpj: '',
name: '',
numberState: '',
cellPhone: '',
whatsapp: false,
email: '',
address: '',
addressNumber: '',
complement: '',
neighborhood: '',
city: '',
state: '',
zipCode: '',
notifications: true,
};
constructor(private readonly customerService: CustomerService,
private dialogService: DialogService,
private dialogsService: MessageService,
private cepService: ConsultaCepService) {
this.form = new FormGroup({
company: new FormControl(this.customerData.company, [
Validators.required,
]),
cpfCnpj: new FormControl(this.customerData.cpfCnpj, [
Validators.required,
]),
name: new FormControl(this.customerData.name, [
Validators.required,
]),
whatsapp: new FormControl(this.customerData.whatsapp, [
Validators.required,
]),
numberState: new FormControl(this.customerData.numberState, []),
cellPhone: new FormControl(this.customerData.cellPhone, [
Validators.required,
]),
email: new FormControl(this.customerData.email, [Validators.required]),
address: new FormControl(this.customerData.address, [Validators.required]),
addressNumber: new FormControl(this.customerData.addressNumber, [Validators.required]),
neighborhood: new FormControl(this.customerData.neighborhood),
complement: new FormControl(this.customerData.complement),
city: new FormControl(this.customerData.city),
state: new FormControl(this.customerData.state),
zipCode: new FormControl(this.customerData.zipCode),
notifications: new FormControl(this.customerData.notifications),
comments: new FormControl(this.customerData.comments),
});
}
public showConfirmation(mensage: string) {
console.log(this.form.value);
const result$ = this.dialogsService.confirmResult;
result$.asObservable()
.pipe(
take(1),
switchMap(result => result ? this.customerService.createCustomer(this.form.value) : EMPTY)
).subscribe(
successCreate => {
return successCreate;
}, err => err
);
this.dialogsService.showConfirmation('Confirmação', mensage);
}
ngOnInit(): void {
}
cpfCadastrado(data: Customer) {
const result$ = this.dialogsService.confirmResult;
result$.asObservable()
.pipe(
take(1),
map(result => result ? this.populateCustomer(data) : this.setFocus('inputCpf')),
// switchMap(result => result ? console.log(result) : EMPTY)
).subscribe(
successCreate => {
return successCreate;
}, err => err
);
this.dialogsService.showConfirmation('Confirmação', 'Cliente já cadastrado, deseja alterar seu cadastro?');
}
populateCustomer(data: Customer) {
this.form.patchValue({
name: data.name,
cellPhone: data.cellPhone,
email: data.email,
zipCode: data.zipCode,
address: data.address,
addressNumber: data.addressNumber,
complement: data.complement,
neighborhood: data.neighborhood,
city: data.city,
state: data.state,
mensage: data.allowMessage,
});
}
searchCustomerByDocument() {
const fieldCpf = 'cpfCnpj';
const cpf = this.form.value[fieldCpf];
this.isloading = true;
this.errorObject = null;
this.customerService.getCustomerbyCpf(cpf).pipe(
map(result => {
if ( result.data != null) {
this.customer = result.data;
console.log(result);
this.cpfCadastrado(result.data);
}
}),
tap(() => {
this.isloading = false;
}),
catchError(err => {
this.isloading = false;
this.errorObject = err;
console.log(err);
return throwError(err);
})).subscribe();
}
setFocus(name) {
this.inputCpf.nativeElement.setFocus();
console.log(name);
/* const ele =
if (ele) {
ele.focus();
}*/
}
createCustomer() {
console.log(this.form.value);
const result$ = this.customerService.createCustomer(this.form.value);
result$.pipe(
map(c => console.log('cliente cadastrado')),
).subscribe();
}
consultaCep() {
const cep = this.form.get('zipCode').value;
if (cep != null && cep !== '') {
this.cepService.consultaCep(cep)
.subscribe(
dados => {
this.populateAddress(dados);
});
}
}
populateAddress(dadosCep: any) {
console.log(dadosCep);
this.form.patchValue({
address: dadosCep.logradouro,
complement: dadosCep.complemento,
neighborhood: dadosCep.bairro,
city: dadosCep.localidade,
state: dadosCep.uf
});
}
}

View File

@@ -0,0 +1,627 @@
<!--Navbar -->
<nav class="navbar navbar-expand-lg fixed-top">
<div class="container-fluid">
<!-- offcanvas trigger-->
<button
class="navbar-toggler"
type="button"
data-bs-toggle="offcanvas"
data-bs-target="#offcanvasExample"
aria-controls="offcanvasExample"
>
<span
class="navbar-toggler-icon"
data-bs-target="#offcanvasExample"
></span>
</button>
<!-- offcanvas trigger-->
<a class="navbar-brand" style="height: 40px; width: 120px" href="#">
<svg
xmlns="http://www.w3.org/2000/svg"
width="230.247"
height="40"
viewBox="0 0 260.247 70.6"
>
<g
id="Grupo_3105"
data-name="Grupo 3105"
transform="translate(-720 -509)"
>
<g id="Grupo_2" data-name="Grupo 2" transform="translate(720 509)">
<path
id="Caminho_1"
data-name="Caminho 1"
d="M4.118,62.728A5.958,5.958,0,0,0,6.5,64.917a7.776,7.776,0,0,0,3.683.822,5.47,5.47,0,0,0,2.859-.685,6.025,6.025,0,0,0,1.891-1.777,8.772,8.772,0,0,0,1.142-2.326q.39-1.233.7-2.395L22.981,23.4H39.033L32.845,61.293a44.545,44.545,0,0,1-1.8,5.642,18.634,18.634,0,0,1-3.523,5.678,18.474,18.474,0,0,1-6.242,4.412A24.1,24.1,0,0,1,11.322,78.8a32.319,32.319,0,0,1-5.462-.445,46.443,46.443,0,0,1-5.179-1.2Z"
transform="translate(-0.681 -8.203)"
fill="#fff"
></path>
<path
id="Caminho_2"
data-name="Caminho 2"
d="M48.366,31.258,45.807,45.086a14.283,14.283,0,0,0-.349,2.679,2.091,2.091,0,0,0,.349,1.315,1.644,1.644,0,0,0,1.337.438,2.183,2.183,0,0,0,2.094-1.046,12.462,12.462,0,0,0,1.047-3.385l2.558-13.828h11.4L61.39,46.4a12.035,12.035,0,0,1-5.233,8.4A18.931,18.931,0,0,1,45.69,57.5q-5.873,0-8.837-2.265a7.582,7.582,0,0,1-2.967-6.4,11.447,11.447,0,0,1,.059-1.168q.057-.583.174-1.266l2.849-15.143Z"
transform="translate(2.993 -7.333)"
fill="#fff"
></path>
<path
id="Caminho_3"
data-name="Caminho 3"
d="M82.473,41.439q-.756-.34-1.57-.633a4.352,4.352,0,0,0-1.454-.292A5.481,5.481,0,0,0,76.8,41.1a5.071,5.071,0,0,0-1.715,1.461,7.524,7.524,0,0,0-1.018,1.948,12.739,12.739,0,0,0-.552,2.094L71.6,57.021H60.2L64.97,31.311H76.425l-1.57,4.918.117.1a11.9,11.9,0,0,1,3.692-3.945A9.418,9.418,0,0,1,84.1,30.776h.349Z"
transform="translate(5.905 -7.386)"
fill="#fff"
></path>
<path
id="Caminho_4"
data-name="Caminho 4"
d="M96.512,31.258,93.955,45.086a14.19,14.19,0,0,0-.349,2.679,2.084,2.084,0,0,0,.349,1.315,1.643,1.643,0,0,0,1.337.438,2.181,2.181,0,0,0,2.092-1.046,12.462,12.462,0,0,0,1.047-3.385l2.559-13.828h11.4L109.538,46.4a12.033,12.033,0,0,1-5.234,8.4,18.927,18.927,0,0,1-10.466,2.7q-5.874,0-8.839-2.265a7.584,7.584,0,0,1-2.965-6.4q0-.583.058-1.168t.174-1.266l2.85-15.143Z"
transform="translate(8.321 -7.333)"
fill="#fff"
></path>
<path
id="Caminho_5"
data-name="Caminho 5"
d="M121.978,36.083l.057.1a9.7,9.7,0,0,1,1.542-2,12.635,12.635,0,0,1,2.122-1.728,11.456,11.456,0,0,1,2.5-1.217,8.3,8.3,0,0,1,2.733-.462,8.924,8.924,0,0,1,3.226.511,5.36,5.36,0,0,1,2.094,1.387,5,5,0,0,1,1.105,2.046,9.366,9.366,0,0,1,.32,2.482,11.986,11.986,0,0,1-.087,1.413q-.088.731-.2,1.462l-3.14,16.944h-11.4l2.385-13a10.485,10.485,0,0,0,.174-1.046,8.429,8.429,0,0,0,.059-.95,2.249,2.249,0,0,0-.321-1.291,1.5,1.5,0,0,0-1.307-.463,2.205,2.205,0,0,0-2.239,1.218,15.442,15.442,0,0,0-.96,3.164l-2.268,12.368h-11.4l4.768-25.709h11.4Z"
transform="translate(11.081 -7.386)"
fill="#fff"
></path>
<path
id="Caminho_6"
data-name="Caminho 6"
d="M162.677,48.305a13.84,13.84,0,0,1-5.989,6.865,18.263,18.263,0,0,1-9.305,2.386,17.484,17.484,0,0,1-5.349-.731,10.65,10.65,0,0,1-3.78-2.045,8.059,8.059,0,0,1-2.239-3.14,10.9,10.9,0,0,1-.727-4.067,11.78,11.78,0,0,1,.088-1.412q.087-.73.2-1.509a16.96,16.96,0,0,1,1.948-5.282,16.78,16.78,0,0,1,3.6-4.407,17.261,17.261,0,0,1,11.543-4.187,13.3,13.3,0,0,1,5.873,1.144,9.509,9.509,0,0,1,3.663,3.043,9.254,9.254,0,0,1,1.4,2.97,12.541,12.541,0,0,1,.407,3.165,21.587,21.587,0,0,1-.145,2.507,25.718,25.718,0,0,1-.436,2.557H146.686q-.058.342-.088.682t-.028.73a3.728,3.728,0,0,0,.406,1.754,1.719,1.719,0,0,0,1.686.78,3.091,3.091,0,0,0,2.85-1.8ZM152.965,41a1.343,1.343,0,0,0,.059-.39v-.389a3.273,3.273,0,0,0-.465-1.7,1.863,1.863,0,0,0-1.744-.779,2.629,2.629,0,0,0-1.279.317,3.052,3.052,0,0,0-.961.8,4.361,4.361,0,0,0-.61,1.072A4.291,4.291,0,0,0,147.674,41Z"
transform="translate(14.213 -7.386)"
fill="#fff"
></path>
<path
id="Caminho_7"
data-name="Caminho 7"
d="M175.239,36.083l.057.1a9.67,9.67,0,0,1,1.543-2,12.582,12.582,0,0,1,2.121-1.728,11.441,11.441,0,0,1,2.5-1.217,8.285,8.285,0,0,1,2.732-.462,8.919,8.919,0,0,1,3.226.511,5.373,5.373,0,0,1,2.095,1.387,5.011,5.011,0,0,1,1.1,2.046,9.367,9.367,0,0,1,.32,2.482,11.983,11.983,0,0,1-.087,1.413q-.087.731-.2,1.462l-3.14,16.944h-11.4l2.385-13a10.182,10.182,0,0,0,.174-1.046,8.425,8.425,0,0,0,.059-.95,2.249,2.249,0,0,0-.321-1.291,1.5,1.5,0,0,0-1.307-.463,2.205,2.205,0,0,0-2.239,1.218,15.443,15.443,0,0,0-.96,3.164l-2.267,12.368h-11.4L165,31.311h11.4Z"
transform="translate(16.974 -7.386)"
fill="#fff"
></path>
<path
id="Caminho_8"
data-name="Caminho 8"
d="M191.086,47.769a9.759,9.759,0,0,0,2.24,1.8,5.623,5.623,0,0,0,2.994.876,4.085,4.085,0,0,0,1.54-.317,1.31,1.31,0,0,0,.9-1v-.244a1.188,1.188,0,0,0-.641-1,7.9,7.9,0,0,0-1.977-.8,22.373,22.373,0,0,1-2.617-1,9.351,9.351,0,0,1-2.121-1.315,5.851,5.851,0,0,1-1.425-1.729,4.763,4.763,0,0,1-.523-2.288c0-.194.009-.4.029-.609s.048-.446.087-.705a8.21,8.21,0,0,1,1.57-3.6,10.8,10.8,0,0,1,3.082-2.727,15.743,15.743,0,0,1,4.245-1.728,20.713,20.713,0,0,1,9.768-.049,18.056,18.056,0,0,1,4.246,1.534l-5.176,6.963q-.873-.778-1.89-1.534a4.034,4.034,0,0,0-2.471-.755,2.519,2.519,0,0,0-1.222.318,1.306,1.306,0,0,0-.7.948V39a1.105,1.105,0,0,0,.32.78,3.326,3.326,0,0,0,.785.609,7.057,7.057,0,0,0,.96.463c.329.13.63.243.9.341a15.387,15.387,0,0,1,4.419,2.239,4.543,4.543,0,0,1,1.8,3.847c0,.194-.01.4-.029.609s-.049.431-.087.656a8.652,8.652,0,0,1-1.745,3.872,11.922,11.922,0,0,1-3.255,2.823,15.688,15.688,0,0,1-4.246,1.729,19.246,19.246,0,0,1-4.71.584,20.478,20.478,0,0,1-5.611-.706,27.977,27.977,0,0,1-4.971-1.971Z"
transform="translate(19.776 -7.386)"
fill="#fff"
></path>
<path
id="Caminho_9"
data-name="Caminho 9"
d="M236.524,48.305a13.835,13.835,0,0,1-5.989,6.865,18.259,18.259,0,0,1-9.3,2.386,17.484,17.484,0,0,1-5.349-.731,10.64,10.64,0,0,1-3.78-2.045,8.059,8.059,0,0,1-2.239-3.14,10.9,10.9,0,0,1-.727-4.067,11.786,11.786,0,0,1,.088-1.412q.087-.73.2-1.509a17.016,17.016,0,0,1,1.948-5.282,16.807,16.807,0,0,1,3.605-4.407,17.261,17.261,0,0,1,11.543-4.187A13.3,13.3,0,0,1,232.4,31.92a9.506,9.506,0,0,1,3.662,3.043,9.207,9.207,0,0,1,1.4,2.97,12.491,12.491,0,0,1,.408,3.165,21.843,21.843,0,0,1-.145,2.507q-.147,1.243-.436,2.557H220.533q-.058.342-.088.682t-.028.73a3.728,3.728,0,0,0,.405,1.754,1.722,1.722,0,0,0,1.687.78,3.091,3.091,0,0,0,2.85-1.8Zm-9.71-7.3a1.383,1.383,0,0,0,.059-.39v-.389a3.273,3.273,0,0,0-.465-1.7,1.863,1.863,0,0,0-1.744-.779,2.636,2.636,0,0,0-1.281.317,3.048,3.048,0,0,0-.96.8,4.361,4.361,0,0,0-.61,1.072A4.292,4.292,0,0,0,221.522,41Z"
transform="translate(22.385 -7.386)"
fill="#fff"
></path>
<path
id="Caminho_10"
data-name="Caminho 10"
d="M37.494,22.3H21.116L23.089,9.717H39.467Z"
transform="translate(1.58 -9.717)"
fill="#ef7d00"
></path>
<g
id="Grupo_1"
data-name="Grupo 1"
transform="translate(64.066 56.235)"
>
<path
id="Caminho_11"
data-name="Caminho 11"
d="M60.329,60.528h4.356l-.663,4.19h2.772l.662-4.19h4.355L69.846,72.966H65.49l.683-4.322H63.4l-.683,4.322H58.364Z"
transform="translate(-58.364 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_12"
data-name="Caminho 12"
d="M85.916,66.8a7.694,7.694,0,0,1-7.888,6.384c-3.794,0-6.5-2.391-5.87-6.384a7.837,7.837,0,0,1,7.9-6.451C83.833,60.349,86.533,62.89,85.916,66.8Zm-9.215.067a1.887,1.887,0,0,0,1.947,2.391,2.726,2.726,0,0,0,2.7-2.391,1.922,1.922,0,0,0-1.943-2.426A2.783,2.783,0,0,0,76.7,66.866Z"
transform="translate(-56.848 -60.349)"
fill="#ef7d00"
></path>
<path
id="Caminho_13"
data-name="Caminho 13"
d="M89.755,60.528h4.651l.684,6.533h.116a15.687,15.687,0,0,1,.573-1.65l2.175-4.882h4.6l.08,12.438H98.265l.466-6.813h-.083a12.046,12.046,0,0,1-.492,1.237l-2.679,5.575h-2.64L92.052,67.7a8.132,8.132,0,0,1-.036-1.55h-.148c-.112.494-.225,1.006-.353,1.5l-1.367,5.312H85.777Z"
transform="translate(-55.331 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_14"
data-name="Caminho 14"
d="M105.37,60.528h8.363l-.536,3.4h-3.811l-.188,1.188h3.481l-.511,3.233h-3.481l-.193,1.221h3.943l-.538,3.4h-8.5Z"
transform="translate(-53.38 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_15"
data-name="Caminho 15"
d="M131.541,65.6a3.375,3.375,0,0,0-2.458-1.254,2.962,2.962,0,0,0-2.841,2.425,2.065,2.065,0,0,0,2.14,2.426,4.238,4.238,0,0,0,2.772-1.155l-.866,4.653a10.737,10.737,0,0,1-3.3.494,5.2,5.2,0,0,1-5.322-6.3,7.861,7.861,0,0,1,7.531-6.533,8.741,8.741,0,0,1,2.954.512Z"
transform="translate(-51.368 -60.349)"
fill="#ef7d00"
></path>
<path
id="Caminho_16"
data-name="Caminho 16"
d="M133.985,60.528h8.364l-.538,3.4H138l-.188,1.188h3.481l-.51,3.233H137.3l-.193,1.221h3.943l-.538,3.4h-8.5Z"
transform="translate(-50.214 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_17"
data-name="Caminho 17"
d="M144.395,60.528h4.339l2.969,6.9h.131a18.385,18.385,0,0,1,.121-3.168l.59-3.728h4.322L154.9,72.966h-4.323l-2.943-6.533H147.5a14.36,14.36,0,0,1-.112,2.491l-.64,4.042H142.43Z"
transform="translate(-49.062 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_18"
data-name="Caminho 18"
d="M157.643,60.528h9.5l-.639,4.042-2.473-.116-1.345,8.512h-4.52l1.346-8.512L157,64.57Z"
transform="translate(-47.449 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_19"
data-name="Caminho 19"
d="M168.482,60.528h8.364l-.538,3.4H172.5l-.188,1.188h3.481l-.51,3.233H171.8l-.193,1.221h3.943l-.538,3.4h-8.5Z"
transform="translate(-46.397 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_20"
data-name="Caminho 20"
d="M178.952,60.528h5.46c2.8,0,4.992,1.187,4.5,4.322a3.571,3.571,0,0,1-2.92,3.234l-.016.1a2.5,2.5,0,0,1,.642.742l2.067,4.042h-5.213l-1.348-3.992h-.082l-.631,3.992h-4.421Zm3.55,5.51h.314c.742,0,1.5-.116,1.648-1.04.151-.957-.506-1.073-1.282-1.073h-.347Z"
transform="translate(-45.238 -60.329)"
fill="#ef7d00"
></path>
</g>
</g>
</g>
</svg>
</a>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!--form class="d-flex ms-auto">
<div class="input-group my-3 my-lg-0">
<input
class="form-control me-2"
type="search"
placeholder="Search"
aria-label="Search"
/>
<button class="btn btn-outline-success" type="submit">Search</button>
</div>
</form-->
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
<li class="nav-item dropdown">
<a
class="nav-link dropdown-toggle"
href="#"
id="navbarDropdown"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<i class="bi bi-person-fill"></i>
</a>
<ul
class="dropdown-menu dropdown-menu-end"
aria-labelledby="navbarDropdown"
>
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><hr class="dropdown-divider" /></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<!-- Navbar -->
<!-- OffCanvas -->
<div
class="offcanvas offcanvas-start sidebar-nav text-light"
data-bs-backdrop="false"
data-bs-scroll="true"
tabindex="-1"
id="offcanvasExample"
aria-labelledby="offcanvasExampleLabel"
>
<div class="offcanvas-header mt-2">
<h5 class="offcanvas-title" id="offcanvasExampleLabel">Mestre Jurunense</h5>
</div>
<div class="offcanvas-body">
<ul class="navbar-nav">
<!--li class="nav-item">
<a
class="nav-link px-3 sidebar-link"
>
<span><i class="bi bi-graph-up-arrow me-2"></i></span>
<span>Dashboard</span>
</a>
</li-->
<li class="nav-item">
<a
class="nav-link px-3 sidebar-link"
data-bs-toggle="collapse"
href="#collapseExample"
role="button"
aria-expanded="false"
aria-controls="collapseExample"
>
<span><i class="bi bi-shop me-2"></i></span>
<span>Cadastros</span>
<span class="right-icon ms-auto"
><i class="bi bi-chevron-down"></i
></span>
</a>
<div class="collapse" id="collapseExample">
<div>
<ul class="navbar-nav ps-3">
<li>
<a href="#" class="nav-link px-3">
<span>Parceiros</span>
</a>
</li>
<li>
<a href="#" class="nav-link px-3">
<span>Categoria</span>
</a>
</li>
<li>
<a href="#" class="nav-link px-3">
<span>Faixa de comissão</span>
</a>
</li>
</ul>
</div>
</div>
</li>
<li>
<ul class="navbar-nav">
<li class="nav-item">
<a
class="nav-link px-3 sidebar-link"
data-bs-toggle="collapse"
href="#collapseregister"
role="button"
aria-expanded="false"
aria-controls="collapseregister"
>
<span><i class="bi bi-person-plus me-2"></i></span>
<span>Cadastros</span>
<span class="right-icon ms-auto"
><i class="bi bi-chevron-down"></i
></span>
</a>
<div class="collapse" id="collapseregister">
<div>
<ul class="navbar-nav ps-3">
<li>
<a href="#" class="nav-link px-3">
<span>Clientes</span>
</a>
</li>
</ul>
</div>
</div>
</li>
</ul>
</li>
</ul>
</div>
</div>
<!-- OffCanvas -->
<main class="mt-5 pt-3">
<div class="container-fluid">
<span>teste</span>
<router-outlet></router-outlet>
</div>
</main>
<!--div class="container-fluid my-0 p-0">
<nav
class="
navbar navbar-expand-md
flex-md-column flex-row
align-items-center
py-2
text-center
sticky-top
"
>
<div class="container-fluid my-0 p-0 sticky-top">
<a class="navbar-brand" href="#">
<svg
xmlns="http://www.w3.org/2000/svg"
width="230.247"
height="50.6"
viewBox="0 0 260.247 70.6"
>
<g
id="Grupo_3105"
data-name="Grupo 3105"
transform="translate(-720 -509)"
>
<g id="Grupo_2" data-name="Grupo 2" transform="translate(720 509)">
<path
id="Caminho_1"
data-name="Caminho 1"
d="M4.118,62.728A5.958,5.958,0,0,0,6.5,64.917a7.776,7.776,0,0,0,3.683.822,5.47,5.47,0,0,0,2.859-.685,6.025,6.025,0,0,0,1.891-1.777,8.772,8.772,0,0,0,1.142-2.326q.39-1.233.7-2.395L22.981,23.4H39.033L32.845,61.293a44.545,44.545,0,0,1-1.8,5.642,18.634,18.634,0,0,1-3.523,5.678,18.474,18.474,0,0,1-6.242,4.412A24.1,24.1,0,0,1,11.322,78.8a32.319,32.319,0,0,1-5.462-.445,46.443,46.443,0,0,1-5.179-1.2Z"
transform="translate(-0.681 -8.203)"
fill="#fff"
></path>
<path
id="Caminho_2"
data-name="Caminho 2"
d="M48.366,31.258,45.807,45.086a14.283,14.283,0,0,0-.349,2.679,2.091,2.091,0,0,0,.349,1.315,1.644,1.644,0,0,0,1.337.438,2.183,2.183,0,0,0,2.094-1.046,12.462,12.462,0,0,0,1.047-3.385l2.558-13.828h11.4L61.39,46.4a12.035,12.035,0,0,1-5.233,8.4A18.931,18.931,0,0,1,45.69,57.5q-5.873,0-8.837-2.265a7.582,7.582,0,0,1-2.967-6.4,11.447,11.447,0,0,1,.059-1.168q.057-.583.174-1.266l2.849-15.143Z"
transform="translate(2.993 -7.333)"
fill="#fff"
></path>
<path
id="Caminho_3"
data-name="Caminho 3"
d="M82.473,41.439q-.756-.34-1.57-.633a4.352,4.352,0,0,0-1.454-.292A5.481,5.481,0,0,0,76.8,41.1a5.071,5.071,0,0,0-1.715,1.461,7.524,7.524,0,0,0-1.018,1.948,12.739,12.739,0,0,0-.552,2.094L71.6,57.021H60.2L64.97,31.311H76.425l-1.57,4.918.117.1a11.9,11.9,0,0,1,3.692-3.945A9.418,9.418,0,0,1,84.1,30.776h.349Z"
transform="translate(5.905 -7.386)"
fill="#fff"
></path>
<path
id="Caminho_4"
data-name="Caminho 4"
d="M96.512,31.258,93.955,45.086a14.19,14.19,0,0,0-.349,2.679,2.084,2.084,0,0,0,.349,1.315,1.643,1.643,0,0,0,1.337.438,2.181,2.181,0,0,0,2.092-1.046,12.462,12.462,0,0,0,1.047-3.385l2.559-13.828h11.4L109.538,46.4a12.033,12.033,0,0,1-5.234,8.4,18.927,18.927,0,0,1-10.466,2.7q-5.874,0-8.839-2.265a7.584,7.584,0,0,1-2.965-6.4q0-.583.058-1.168t.174-1.266l2.85-15.143Z"
transform="translate(8.321 -7.333)"
fill="#fff"
></path>
<path
id="Caminho_5"
data-name="Caminho 5"
d="M121.978,36.083l.057.1a9.7,9.7,0,0,1,1.542-2,12.635,12.635,0,0,1,2.122-1.728,11.456,11.456,0,0,1,2.5-1.217,8.3,8.3,0,0,1,2.733-.462,8.924,8.924,0,0,1,3.226.511,5.36,5.36,0,0,1,2.094,1.387,5,5,0,0,1,1.105,2.046,9.366,9.366,0,0,1,.32,2.482,11.986,11.986,0,0,1-.087,1.413q-.088.731-.2,1.462l-3.14,16.944h-11.4l2.385-13a10.485,10.485,0,0,0,.174-1.046,8.429,8.429,0,0,0,.059-.95,2.249,2.249,0,0,0-.321-1.291,1.5,1.5,0,0,0-1.307-.463,2.205,2.205,0,0,0-2.239,1.218,15.442,15.442,0,0,0-.96,3.164l-2.268,12.368h-11.4l4.768-25.709h11.4Z"
transform="translate(11.081 -7.386)"
fill="#fff"
></path>
<path
id="Caminho_6"
data-name="Caminho 6"
d="M162.677,48.305a13.84,13.84,0,0,1-5.989,6.865,18.263,18.263,0,0,1-9.305,2.386,17.484,17.484,0,0,1-5.349-.731,10.65,10.65,0,0,1-3.78-2.045,8.059,8.059,0,0,1-2.239-3.14,10.9,10.9,0,0,1-.727-4.067,11.78,11.78,0,0,1,.088-1.412q.087-.73.2-1.509a16.96,16.96,0,0,1,1.948-5.282,16.78,16.78,0,0,1,3.6-4.407,17.261,17.261,0,0,1,11.543-4.187,13.3,13.3,0,0,1,5.873,1.144,9.509,9.509,0,0,1,3.663,3.043,9.254,9.254,0,0,1,1.4,2.97,12.541,12.541,0,0,1,.407,3.165,21.587,21.587,0,0,1-.145,2.507,25.718,25.718,0,0,1-.436,2.557H146.686q-.058.342-.088.682t-.028.73a3.728,3.728,0,0,0,.406,1.754,1.719,1.719,0,0,0,1.686.78,3.091,3.091,0,0,0,2.85-1.8ZM152.965,41a1.343,1.343,0,0,0,.059-.39v-.389a3.273,3.273,0,0,0-.465-1.7,1.863,1.863,0,0,0-1.744-.779,2.629,2.629,0,0,0-1.279.317,3.052,3.052,0,0,0-.961.8,4.361,4.361,0,0,0-.61,1.072A4.291,4.291,0,0,0,147.674,41Z"
transform="translate(14.213 -7.386)"
fill="#fff"
></path>
<path
id="Caminho_7"
data-name="Caminho 7"
d="M175.239,36.083l.057.1a9.67,9.67,0,0,1,1.543-2,12.582,12.582,0,0,1,2.121-1.728,11.441,11.441,0,0,1,2.5-1.217,8.285,8.285,0,0,1,2.732-.462,8.919,8.919,0,0,1,3.226.511,5.373,5.373,0,0,1,2.095,1.387,5.011,5.011,0,0,1,1.1,2.046,9.367,9.367,0,0,1,.32,2.482,11.983,11.983,0,0,1-.087,1.413q-.087.731-.2,1.462l-3.14,16.944h-11.4l2.385-13a10.182,10.182,0,0,0,.174-1.046,8.425,8.425,0,0,0,.059-.95,2.249,2.249,0,0,0-.321-1.291,1.5,1.5,0,0,0-1.307-.463,2.205,2.205,0,0,0-2.239,1.218,15.443,15.443,0,0,0-.96,3.164l-2.267,12.368h-11.4L165,31.311h11.4Z"
transform="translate(16.974 -7.386)"
fill="#fff"
></path>
<path
id="Caminho_8"
data-name="Caminho 8"
d="M191.086,47.769a9.759,9.759,0,0,0,2.24,1.8,5.623,5.623,0,0,0,2.994.876,4.085,4.085,0,0,0,1.54-.317,1.31,1.31,0,0,0,.9-1v-.244a1.188,1.188,0,0,0-.641-1,7.9,7.9,0,0,0-1.977-.8,22.373,22.373,0,0,1-2.617-1,9.351,9.351,0,0,1-2.121-1.315,5.851,5.851,0,0,1-1.425-1.729,4.763,4.763,0,0,1-.523-2.288c0-.194.009-.4.029-.609s.048-.446.087-.705a8.21,8.21,0,0,1,1.57-3.6,10.8,10.8,0,0,1,3.082-2.727,15.743,15.743,0,0,1,4.245-1.728,20.713,20.713,0,0,1,9.768-.049,18.056,18.056,0,0,1,4.246,1.534l-5.176,6.963q-.873-.778-1.89-1.534a4.034,4.034,0,0,0-2.471-.755,2.519,2.519,0,0,0-1.222.318,1.306,1.306,0,0,0-.7.948V39a1.105,1.105,0,0,0,.32.78,3.326,3.326,0,0,0,.785.609,7.057,7.057,0,0,0,.96.463c.329.13.63.243.9.341a15.387,15.387,0,0,1,4.419,2.239,4.543,4.543,0,0,1,1.8,3.847c0,.194-.01.4-.029.609s-.049.431-.087.656a8.652,8.652,0,0,1-1.745,3.872,11.922,11.922,0,0,1-3.255,2.823,15.688,15.688,0,0,1-4.246,1.729,19.246,19.246,0,0,1-4.71.584,20.478,20.478,0,0,1-5.611-.706,27.977,27.977,0,0,1-4.971-1.971Z"
transform="translate(19.776 -7.386)"
fill="#fff"
></path>
<path
id="Caminho_9"
data-name="Caminho 9"
d="M236.524,48.305a13.835,13.835,0,0,1-5.989,6.865,18.259,18.259,0,0,1-9.3,2.386,17.484,17.484,0,0,1-5.349-.731,10.64,10.64,0,0,1-3.78-2.045,8.059,8.059,0,0,1-2.239-3.14,10.9,10.9,0,0,1-.727-4.067,11.786,11.786,0,0,1,.088-1.412q.087-.73.2-1.509a17.016,17.016,0,0,1,1.948-5.282,16.807,16.807,0,0,1,3.605-4.407,17.261,17.261,0,0,1,11.543-4.187A13.3,13.3,0,0,1,232.4,31.92a9.506,9.506,0,0,1,3.662,3.043,9.207,9.207,0,0,1,1.4,2.97,12.491,12.491,0,0,1,.408,3.165,21.843,21.843,0,0,1-.145,2.507q-.147,1.243-.436,2.557H220.533q-.058.342-.088.682t-.028.73a3.728,3.728,0,0,0,.405,1.754,1.722,1.722,0,0,0,1.687.78,3.091,3.091,0,0,0,2.85-1.8Zm-9.71-7.3a1.383,1.383,0,0,0,.059-.39v-.389a3.273,3.273,0,0,0-.465-1.7,1.863,1.863,0,0,0-1.744-.779,2.636,2.636,0,0,0-1.281.317,3.048,3.048,0,0,0-.96.8,4.361,4.361,0,0,0-.61,1.072A4.292,4.292,0,0,0,221.522,41Z"
transform="translate(22.385 -7.386)"
fill="#fff"
></path>
<path
id="Caminho_10"
data-name="Caminho 10"
d="M37.494,22.3H21.116L23.089,9.717H39.467Z"
transform="translate(1.58 -9.717)"
fill="#ef7d00"
></path>
<g
id="Grupo_1"
data-name="Grupo 1"
transform="translate(64.066 56.235)"
>
<path
id="Caminho_11"
data-name="Caminho 11"
d="M60.329,60.528h4.356l-.663,4.19h2.772l.662-4.19h4.355L69.846,72.966H65.49l.683-4.322H63.4l-.683,4.322H58.364Z"
transform="translate(-58.364 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_12"
data-name="Caminho 12"
d="M85.916,66.8a7.694,7.694,0,0,1-7.888,6.384c-3.794,0-6.5-2.391-5.87-6.384a7.837,7.837,0,0,1,7.9-6.451C83.833,60.349,86.533,62.89,85.916,66.8Zm-9.215.067a1.887,1.887,0,0,0,1.947,2.391,2.726,2.726,0,0,0,2.7-2.391,1.922,1.922,0,0,0-1.943-2.426A2.783,2.783,0,0,0,76.7,66.866Z"
transform="translate(-56.848 -60.349)"
fill="#ef7d00"
></path>
<path
id="Caminho_13"
data-name="Caminho 13"
d="M89.755,60.528h4.651l.684,6.533h.116a15.687,15.687,0,0,1,.573-1.65l2.175-4.882h4.6l.08,12.438H98.265l.466-6.813h-.083a12.046,12.046,0,0,1-.492,1.237l-2.679,5.575h-2.64L92.052,67.7a8.132,8.132,0,0,1-.036-1.55h-.148c-.112.494-.225,1.006-.353,1.5l-1.367,5.312H85.777Z"
transform="translate(-55.331 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_14"
data-name="Caminho 14"
d="M105.37,60.528h8.363l-.536,3.4h-3.811l-.188,1.188h3.481l-.511,3.233h-3.481l-.193,1.221h3.943l-.538,3.4h-8.5Z"
transform="translate(-53.38 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_15"
data-name="Caminho 15"
d="M131.541,65.6a3.375,3.375,0,0,0-2.458-1.254,2.962,2.962,0,0,0-2.841,2.425,2.065,2.065,0,0,0,2.14,2.426,4.238,4.238,0,0,0,2.772-1.155l-.866,4.653a10.737,10.737,0,0,1-3.3.494,5.2,5.2,0,0,1-5.322-6.3,7.861,7.861,0,0,1,7.531-6.533,8.741,8.741,0,0,1,2.954.512Z"
transform="translate(-51.368 -60.349)"
fill="#ef7d00"
></path>
<path
id="Caminho_16"
data-name="Caminho 16"
d="M133.985,60.528h8.364l-.538,3.4H138l-.188,1.188h3.481l-.51,3.233H137.3l-.193,1.221h3.943l-.538,3.4h-8.5Z"
transform="translate(-50.214 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_17"
data-name="Caminho 17"
d="M144.395,60.528h4.339l2.969,6.9h.131a18.385,18.385,0,0,1,.121-3.168l.59-3.728h4.322L154.9,72.966h-4.323l-2.943-6.533H147.5a14.36,14.36,0,0,1-.112,2.491l-.64,4.042H142.43Z"
transform="translate(-49.062 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_18"
data-name="Caminho 18"
d="M157.643,60.528h9.5l-.639,4.042-2.473-.116-1.345,8.512h-4.52l1.346-8.512L157,64.57Z"
transform="translate(-47.449 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_19"
data-name="Caminho 19"
d="M168.482,60.528h8.364l-.538,3.4H172.5l-.188,1.188h3.481l-.51,3.233H171.8l-.193,1.221h3.943l-.538,3.4h-8.5Z"
transform="translate(-46.397 -60.329)"
fill="#ef7d00"
></path>
<path
id="Caminho_20"
data-name="Caminho 20"
d="M178.952,60.528h5.46c2.8,0,4.992,1.187,4.5,4.322a3.571,3.571,0,0,1-2.92,3.234l-.016.1a2.5,2.5,0,0,1,.642.742l2.067,4.042h-5.213l-1.348-3.992h-.082l-.631,3.992h-4.421Zm3.55,5.51h.314c.742,0,1.5-.116,1.648-1.04.151-.957-.506-1.073-1.282-1.073h-.347Z"
transform="translate(-45.238 -60.329)"
fill="#ef7d00"
></path>
</g>
</g>
</g>
</svg>
</a>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#nav"
aria-controls="nav"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
<div class="row min-vh-100 flex-column flex-md-row">
<aside class="col-12 col-md-3 col-xl-2 p-0 bg-dark">
<nav
class="
navbar navbar-expand-md navbar-dark
bd-dark
flex-md-column flex-row
align-items-center
py-2
text-center
"
id="sidebar"
>
<div class="text-center p-3">
<img
src="https://impreza.us-themes.com/wp-content/uploads/paolo-bendandi-D-8XODEIr_s-unsplash.jpg"
alt="profile picture"
class="img-fluid rounded-circle my-4 p-1 d-none d-md-block shadow"
/>
<a href="#" class="navbar-brand mx-0 font-weight-bold text-nowrap"
>XcentPupil</a
>
</div>
<button
type="button"
class="navbar-toggler border-0 order-1"
data-bs-toggle="collapse"
data-bs-target="#nav"
aria-controls="nav"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse order-last" id="nav">
<ul class="navbar-nav flex-column w-100 justify-content-center">
<li class="nav-item">
<a href="#" class="nav-link active"> Edit Profile</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link"> Projects</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link"> Tasks </a>
</li>
<li class="nav-item">
<a href="#" class="nav-link"> Users Info </a>
</li>
</ul>
</div>
</nav>
</aside>
<main class="col px-0 flex-grow-1 overflow-auto">
<div class="container py-3">
<router-outlet></router-outlet>
</div>
</main>
</div>
</!--div>
<!--div class="container-fluid">
<div class="row">
<div class="col-2">
<div class="d-line" style="width: 240px; left: -240;">
<div class="sidebar fixed">
<span class="fs-5 fw-semibold">MENU</span>
<ul class="list-unstyled ps-0">
<li class="mb-1">
<button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#home-collapse" aria-expanded="true">
Cadastro
</button>
<div class="collapse show" id="home-collapse">
<ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
<li><a href="#" class="link-dark rounded">Clientes</a></li>
</ul>
</div>
</li>
<li class="border-top my-3"></li>
<li class="mb-1">
<button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#account-collapse" aria-expanded="false">
Tabelas auxiliares
</button>
<div class="collapse" id="account-collapse">
<ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
<li><a href="#" class="link-dark rounded">Fidelidade</a></li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="col-10">
<router-outlet></router-outlet>
</div>
</div>
</div-->

View File

@@ -0,0 +1,64 @@
.navbar {
background-color: #2D2E83;
height: 60px;
}
#menu-vertical{
position:fixed;
z-index:999;
overflow:hidden;
padding:6px;
height: 100vh;
background-color: #2D2E83;
}
:root {
--offcanvas-width: 270px;
--topNavbarHeight: 56px;
}
.sidebar-nav {
width: 270px;
background-color: #2D2E83;
}
.sidebar-link {
display: flex;
align-items: center;
}
.sidebar-link .right-icon {
display: inline-flex;
transition: all ease 0.25s;
}
.sidebar-link[aria-expanded="true"] .right-icon {
transform: rotate(180deg);
}
li a {
text-decoration: none;
color: white;
}
@media (min-width: 992px) {
body {
overflow: auto !important;
}
main {
margin-left: 270px;
}
.offcanvas-backdrop::before{
display: none;
}
.sidebar-nav{
transform: none;
visibility: visible !important;
top: 56px;
height: calc(100% - 56px);
}
}

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MenuCrmComponent } from './menu-crm.component';
describe('MenuCrmComponent', () => {
let component: MenuCrmComponent;
let fixture: ComponentFixture<MenuCrmComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MenuCrmComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MenuCrmComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,18 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-menu-crm',
templateUrl: './menu-crm.component.html',
styleUrls: ['./menu-crm.component.scss']
})
export class MenuCrmComponent implements OnInit {
constructor() { }
status: boolean = false;
clickEvent(){
this.status = !this.status;
}
ngOnInit(): void {
}
}

View File

@@ -0,0 +1,105 @@
<div class="container">
<nav class="navbar navbar-expand-lg navbar-light bg-danger">
<div class="container-fluid">
<a class="navbar-brand text-white" href="#">Financial</a>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarNav"
aria-controls="navbarNav"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Features</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Pricing</a>
</li>
<li class="nav-item">
<a
class="nav-link disabled"
href="#"
tabindex="-1"
aria-disabled="true"
>Disabled</a
>
</li>
</ul>
</div>
</div>
</nav>
<div class="card mt-3">
<h2 class="card-header">Conferência de caixa</h2>
<form class="mt-3 px-3" action="">
<div class="mb-3">
<kendo-floatinglabel text="Loja">
<kendo-combobox
style="width: 450px"
[data]="stores"
[textField]="'name'"
[valueField]="'id'"
[placeholder]="'Selecione a loja desejada'"
(valueChange)="handleStoreChange($event)"
></kendo-combobox>
</kendo-floatinglabel>
</div>
<div class="mb-3">
<kendo-floatinglabel text="Caixa">
<kendo-combobox
style="width: 450px"
[disabled]="isDisabledCheckout"
[data]="checkouts"
[textField]="'description'"
[valueField]="'id'"
[placeholder]="'Selecione o checkout desejado'"
(valueChange)="handleCheckoutChange($event)"
></kendo-combobox>
</kendo-floatinglabel>
</div>
<div class="mb-3">
<kendo-floatinglabel text="Usuário">
<kendo-combobox
style="width: 450px"
[disabled]="isDisabledUser"
[data]="users"
(valueChange)="handleUserChange($event)"
[textField]="'name'"
[valueField]="'id'"
[placeholder]="'Selecione o usuário desejado'"
></kendo-combobox>
</kendo-floatinglabel>
</div>
<div class="mb-3">
<kendo-floatinglabel text="Data movimento">
<kendo-datepicker [format]="format" [(value)]="value"></kendo-datepicker>
</kendo-floatinglabel>
</div>
<div class="row mb-3 mt-3">
<div class="col12">
<button kendoButton look="outline" [primary]="true" (click)="findOrders()">Pesquisar</button>
</div>
</div>
</form>
</div>
</div>
<div class="container">
<kendo-grid>
</kendo-grid>
</div>

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CheckoutComponent } from './checkout.component';
describe('CheckoutComponent', () => {
let component: CheckoutComponent;
let fixture: ComponentFixture<CheckoutComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CheckoutComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CheckoutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,82 @@
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { FormatSettings } from '@progress/kendo-angular-dateinputs';
import { ComboBoxComponent } from '@progress/kendo-angular-dropdowns';
import { CheckoutOrder } from 'src/app/models/checkout-order.model';
import { Checkout } from 'src/app/models/checkout.model';
import { StoreERP } from 'src/app/models/store.model';
import { User } from 'src/app/models/user.model';
import { LookupService } from 'src/app/services/lookup.service';
@Component({
selector: 'app-checkout',
templateUrl: './checkout.component.html',
styleUrls: ['./checkout.component.css']
})
export class CheckoutComponent implements OnInit, OnDestroy {
@ViewChild('combo') public combo: ComboBoxComponent;
public stores: StoreERP[] = [];
public checkouts: Checkout[] = [];
public users: User[] = [];
public checkoutOrders: CheckoutOrder[] = [];
public value: Date = new Date();
public format: FormatSettings = {
displayFormat: 'dd/MM/yyyy',
inputFormat: 'dd/MM/yyyy',
};
public selectStore: StoreERP;
public selectCheckout: Checkout;
public selectUser: User;
public isDisabledCheckout = true;
public isDisabledUser = true;
constructor(private lookupService: LookupService) {}
ngOnInit(): void {
this.lookupService.getStore().subscribe((data) => (this.stores = data));
}
ngOnDestroy(): void {
throw new Error('Method not implemented.');
/*****NAO ESQUECER DO UNSUBSCRIBE************/
}
fechDataStore(idStore: string) {
this.lookupService.getCheckout(idStore).subscribe((data) => (this.checkouts = data));
this.lookupService.getUser(idStore).subscribe((data) => (this.users = data));
}
handleStoreChange(value) {
this.selectStore = value;
if (value === undefined) {
this.isDisabledCheckout = true;
this.checkouts = [];
this.isDisabledUser = true;
this.users = [];
} else {
this.isDisabledCheckout = false;
this.lookupService.getCheckout(value.id).subscribe((data) => (this.checkouts = data));
this.isDisabledUser = false;
this.lookupService.getUser(value.id).subscribe((data) => (this.users = data));
}
}
handleCheckoutChange(value) {
this.selectCheckout = value;
}
handleUserChange(value) {
this.selectUser = value;
}
findOrders(){
console.log(this.selectStore);
console.log(this.selectCheckout);
console.log(this.selectUser);
}
}

View File

@@ -0,0 +1,16 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { CheckoutComponent } from './checkout/checkout.component';
const routes: Routes = [{ path: 'checkout', component: CheckoutComponent }];
@NgModule({
declarations: [],
imports: [
CommonModule,
RouterModule.forChild(routes)
],
exports: [RouterModule]
})
export class FinancialRoutingModule { }

View File

@@ -0,0 +1,18 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CheckoutComponent } from './checkout/checkout.component';
import { FinancialRoutingModule } from './financial-routing.module';
import { KendoModule } from '../shared/kendo.module';
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [CheckoutComponent],
imports: [
CommonModule,
FinancialRoutingModule,
FormsModule,
KendoModule,
]
})
export class FinancialModule { }

View File

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { AuthGuard } from './auth.guard';
describe('AuthGuardService', () => {
let service: AuthGuard;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AuthGuard);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -0,0 +1,24 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../auth/services/auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) { }
canActivate(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | boolean {
if (this.authService.isAuthenticate()) {
return true;
}
this.router.navigate(['/login']);
return false;
}
}

View File

@@ -0,0 +1,30 @@
import { ErrorHandler, Injectable, NgZone } from '@angular/core';
import { DialogService } from '@progress/kendo-angular-dialog';
import { MessageErrorComponent } from '../shared/menssages/message-error/message-error.component';
@Injectable()
export class ErrorsHandler implements ErrorHandler {
constructor(private dialogService: DialogService, private ngZone: NgZone) {}
handleError(error: any) {
console.log(error.message);
const dialogRef = this.dialogService
.open({
title: 'Error Dialog',
content: MessageErrorComponent,
actions: [{ text: 'OK', primary: true }],
width: 400,
height: 550,
minWidth: 250,
});
const messageInfo = dialogRef.content.instance;
messageInfo.status = error.status;
messageInfo.message = error.message;
console.log(error.status + '-' + error.message);
this.ngZone.run(() => {
dialogRef.result.subscribe((result) => console.log(result));
});
}
}

View File

@@ -0,0 +1,188 @@
<header>
<app-header-system></app-header-system>
</header>
<main class="container">
<div id="title-page" class="mt-3 ms-2">
<h1>Selecione o módulo desejado</h1>
</div>
<div class="row g-3 m-2 align-items-center">
<div *ngIf="moduleSale" id="item-module" class="col-12 col-sm-6 col-md-4 col-lg-2 ">
<a (click)="openModule('sales/menu')">
<div class="card">
<div class="card-title">
<svg class="mt-3 m-3" width="55" height="55" viewBox="0 0 90 80" fill="#EC7E31"
xmlns="http://www.w3.org/2000/svg">
<g>
<g>
<path d="M22,66h5c1.1,0,2-0.9,2-2V33c0-1.1-0.9-2-2-2h-5c-1.1,0-2,0.9-2,2v31C20,65.1,20.9,66,22,66z" />
</g>
<g>
<path d="M78,31h-5c-1.1,0-2,0.9-2,2v31c0,1.1,0.9,2,2,2h5c1.1,0,2-0.9,2-2V33C80,31.9,79.1,31,78,31z" />
</g>
<g>
<path d="M53,66c1.1,0,2-0.9,2-2V33c0-1.1-0.9-2-2-2h-6c-1.1,0-2,0.9-2,2v31c0,1.1,0.9,2,2,2H53z" />
</g>
<g>
<path d="M65,66c1.1,0,2-0.9,2-2V33c0-1.1-0.9-2-2-2h-2c-1.1,0-2,0.9-2,2v31c0,1.1,0.9,2,2,2H65z" />
</g>
<g>
<path d="M39,66c1.1,0,2-0.9,2-2V33c0-1.1-0.9-2-2-2h-2c-1.1,0-2,0.9-2,2v31c0,1.1,0.9,2,2,2H39z" />
</g>
<g>
<path d="M78,72H22c-1.1,0-2,0.9-2,2v2c0,1.1,0.9,2,2,2h56c1.1,0,2-0.9,2-2v-2C80,72.9,79.1,72,78,72z" />
</g>
<g>
<path d="M78,20H22c-1.1,0-2,0.9-2,2v2c0,1.1,0.9,2,2,2h56c1.1,0,2-0.9,2-2v-2C80,20.9,79.1,20,78,20z" />
</g>
</g>
</svg>
</div>
<div class="card-body">
<p class="card-text">Vendas</p>
</div>
</div>
</a>
</div>
<div *ngIf="modulePartner" id="item-module" class="col-12 col-sm-6 col-md-4 col-lg-2 align-self-center">
<a (click)="openModule('partner')">
<div class="card">
<div class="card-title">
<svg class="mt-3 m-3" width="55" height="55" viewBox="0 0 90 80" fill="#EC7E31"
xmlns="http://www.w3.org/2000/svg">
<path
d="M56.19,20.52a1.73,1.73,0,0,0-2.47,0l-2.47,2.25a1.62,1.62,0,0,0,0,2.43l4.21,4.08a1.1,1.1,0,0,1-.82,1.9H31.83A1.92,1.92,0,0,0,30,32.92v3.46a1.85,1.85,0,0,0,1.83,1.74H54.64a1.12,1.12,0,0,1,.82,1.9L51.25,44.1a1.62,1.62,0,0,0,0,2.43L53.72,49a1.72,1.72,0,0,0,2.47,0L69.65,36a1.62,1.62,0,0,0,0-2.43ZM44,51.05a1.73,1.73,0,0,1,2.48,0L49,53.3a1.62,1.62,0,0,1,0,2.43L44.74,59.8a1.1,1.1,0,0,0,.82,1.91H68.37a1.92,1.92,0,0,1,1.83,1.73v3.47a1.85,1.85,0,0,1-1.83,1.73H45.56a1.12,1.12,0,0,0-.82,1.91L49,74.63a1.61,1.61,0,0,1,0,2.42l-2.47,2.43a1.74,1.74,0,0,1-2.48,0l-13.45-13a1.62,1.62,0,0,1,0-2.43Z"
fill-rule="evenodd" />
</svg>
</div>
<div class="card-body">
<p class="card-text">Mestre Jurunense</p>
</div>
</div>
</a>
</div>
<div *ngIf="moduleAdmin" id="item-module" class="col-12 col-sm-6 col-md-4 col-lg-2 align-self-center">
<a (click)="openModule('admin/permission-user')">
<div class="card">
<div class="card-title">
<div class="svg-container">
<svg class="mt-3 m-3" width="55" height="55" viewBox="0 0 90 80" fill="#EC7E31"
xmlns="http://www.w3.org/2000/svg">
<g>
<path d="M25.8,60.6h-4.5c-0.7,0-1.3,0.6-1.3,1.3v16.1c0,0.7,0.6,1.3,1.3,1.3h2.2c2,0,3.6-1.6,3.6-3.6V62
C27.2,61.2,26.5,60.6,25.8,60.6z" />
<path d="M79.9,69.4c-0.7-1.6-2-3.3-3.9-3.5c-1-0.1-2,0.3-2.9,0.6c-3.6,1.3-7.2,2.5-10.8,3.8
c-2.3,0.8-4.7,1.6-7.2,1.8c-1.7,0.1-3.4,0-5.1,0c-0.9,0-1.7-0.7-1.7-1.7s0.7-1.7,1.7-1.7l9.1,0c1.7,0,3-1.4,3-3s-1.4-3-3-3h-7
c-0.3,0-2.2-0.1-3.4-0.6c-1.3-0.6-3-0.7-3-0.6c0,0,0,0-0.1,0H33.4c-1.5,0-2.7,1.2-2.7,2.7v11.3c0,1.3,1,2.4,2.3,2.6
c0.1,0,0.2,0,0.3,0c2.3,0,4.6,0.5,6.9,0.9c2.3,0.5,4.5,0.8,6.9,0.8c3,0.1,6.1-0.4,9-1.1c2.9-0.8,5.7-1.9,8.5-2.8
c4.8-1.6,9.7-3.3,14.5-4.9C79.7,70.7,80.2,70.2,79.9,69.4z" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M58,40.1v15c0,0.5,0.5,0.7,0.9,0.6c2.9-1.7,11.9-6.7,11.9-6.7
c1.2-0.7,1.9-1.9,1.9-3.3V32.2c0-0.5-0.5-0.7-0.9-0.6l-13.2,7.4C58.3,39.3,58,39.7,58,40.1" />
<path fill-rule="evenodd" clip-rule="evenodd"
d="M56.8,36L70,28.6c0.4-0.2,0.4-0.8,0-1c-2.9-1.7-12-6.8-12-6.8
c-1.2-0.7-2.6-0.7-3.8,0c0,0-9,5.1-12,6.8c-0.4,0.2-0.4,0.8,0,1L55.6,36C55.9,36.2,56.4,36.2,56.8,36" />
<path fill-rule="evenodd" clip-rule="evenodd"
d="M53.7,39.1l-13.2-7.4c-0.4-0.2-0.9,0.1-0.9,0.6v13.4
c0,1.3,0.7,2.6,1.9,3.3c0,0,9,5.1,11.9,6.7c0.4,0.2,0.9-0.1,0.9-0.6V40.1C54.3,39.7,54.1,39.3,53.7,39.1" />
</g>
</svg>
</div>
</div>
<div class="card-body">
<p class="card-text">Configurações</p>
</div>
</div>
</a>
</div>
</div>
</main>
<!--div class="container mt-3 mb-3 border rounded-3 shadow" style="height: 85vh">
<h1>Selecione o módulo desejado</h1>
<div class="row g-3 m-2 align-items-center">
<div class="col-12 col-sm-6 col-md-4 col-lg-2">
<a href="/#/sales/menu">
<div class="card">
<div class="card-title">
<svg
class="mt-3 m-3"
width="54"
height="55"
viewBox="0 0 54 55"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19.6602 31.7765C24.8584 30.7533 28.443 25.8649 27.9396 20.4861C27.4362 15.1068 23.0092 11 17.7154 11C12.421 11 7.99461 15.1068 7.49064 20.4861C6.98722 25.8649 10.5718 30.7533 15.77 31.7765C6.797 32.8025 0.00929224 40.5424 0 49.7584V55H35.4444V49.7584C35.439 40.5357 28.6414 32.7913 19.6602 31.7765ZM10.257 21.4792C10.257 17.267 13.6022 13.852 17.7291 13.852C21.8559 13.852 25.2017 17.267 25.2017 21.4792C25.2017 25.6914 21.8559 29.1058 17.7291 29.1058C13.6038 29.1019 10.2608 25.6897 10.257 21.4792ZM32.6458 52.1435H2.7986V49.7584C2.7986 41.3418 9.48301 34.5192 17.7291 34.5192C25.9751 34.5192 32.6595 41.3418 32.6595 49.7584V52.1435H32.6458Z"
fill="#EC7E31"
/>
<path
d="M41.2061 0V24.4444"
stroke="#EC7E31"
stroke-width="3"
/>
<path
d="M53.4282 12.6436L28.1108 12.6436"
stroke="#EC7E31"
stroke-width="3"
/>
</svg>
</div>
<div class="card-body">
<p class="card-text">Vendas</p>
</div>
</div>
</a>
</div>
<div class="col-12 col-sm-6 col-md-4 col-lg-2 align-self-center">
<a href="/#/partner">
<div class="card">
<div class="card-title">
<svg
class="mt-3 m-3"
width="54"
height="55"
viewBox="0 0 54 55"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19.6602 31.7765C24.8584 30.7533 28.443 25.8649 27.9396 20.4861C27.4362 15.1068 23.0092 11 17.7154 11C12.421 11 7.99461 15.1068 7.49064 20.4861C6.98722 25.8649 10.5718 30.7533 15.77 31.7765C6.797 32.8025 0.00929224 40.5424 0 49.7584V55H35.4444V49.7584C35.439 40.5357 28.6414 32.7913 19.6602 31.7765ZM10.257 21.4792C10.257 17.267 13.6022 13.852 17.7291 13.852C21.8559 13.852 25.2017 17.267 25.2017 21.4792C25.2017 25.6914 21.8559 29.1058 17.7291 29.1058C13.6038 29.1019 10.2608 25.6897 10.257 21.4792ZM32.6458 52.1435H2.7986V49.7584C2.7986 41.3418 9.48301 34.5192 17.7291 34.5192C25.9751 34.5192 32.6595 41.3418 32.6595 49.7584V52.1435H32.6458Z"
fill="#EC7E31"
/>
<path
d="M41.2061 0V24.4444"
stroke="#EC7E31"
stroke-width="3"
/>
<path
d="M53.4282 12.6436L28.1108 12.6436"
stroke="#EC7E31"
stroke-width="3"
/>
</svg>
</div>
<div class="card-body">
<p class="card-text">Mestre Jurunese</p>
</div>
</div>
</a>
</div>
</div>
<div class="row h-100">
<div class="col-7 p-0">
<img
src="../../assets/img/loja.jpeg"
alt=""
style="width: 100%; height: 100%"
/>
</div>
<div class="col-5" style="background-color: white">
</div>
</div>
</div-->
<footer></footer>

View File

@@ -0,0 +1,182 @@
.row.menu {
height: 90%;
margin: 60px 25px 25px 25px;
background: #f8f8f8;
border-radius: 25px;
}
.wrapper {
height: 90vh;
}
.card {
width: 200px;
height: 160px;
background: #ffffff;
border-radius: 20px;
}
.card-small {
width: 180px;
height: 150px;
background: #ffffff;
border-radius: 20px;
}
.card-text {
width: 170px;
height: 44px;
font-family: Montserrat;
font-style: normal;
font-weight: bold;
font-size: 18px;
line-height: 22px;
text-transform: uppercase;
text-decoration: none;
color: #1c1e54;
}
a {
text-decoration: none;
}
.card:hover {
transform: translateY(-3px);
box-shadow: 0 4px 17px rgba(0, 0, 0, 0.35);
}
.a-wrapper-customer {
width: 95%;
min-height: 95%;
margin-top: 5px;
background: #f8f8f8;
border-radius: 25px;
}
.title {
width: 136px;
height: 44px;
font-family: Montserrat;
font-style: normal;
font-weight: bold;
font-size: 18px;
line-height: 22px;
text-transform: uppercase;
color: #1c1e54;
}
.a-title-page {
width: 290px;
height: 98px;
font-family: Montserrat;
font-style: normal;
font-weight: 300;
font-size: 40px;
line-height: 49px;
color: #6b6ebe;
}
.a-search-customer {
width: 100%;
height: 60px;
background: #ffffff;
border-radius: 20px;
}
.a-input {
height: 27px;
font-family: Montserrat;
font-style: italic;
font-weight: 300;
font-size: 22px;
line-height: 27px;
border: none;
/* identical to box height */
text-align: center;
color: #c4c4c4;
}
.custom-size {
width: 150px;
height: 150px;
}
/* Smartphones */
@media (max-width: 575.98px) {
#title-page {
padding-top: 90px;
}
#item-module {
margin-bottom: 00px;
}
h1{
font-size: 14px;
}
.card {
width: 100%;
height: auto;
}
.card-small {
width: 100%;
height: auto;
}
.card-text {
font-size: 16px;
text-align: center;
}
.row.g-3.m-2.align-items-center {
flex-direction: column;
margin: 0;
}
.container {
padding: 0 10px;
}
}
/* Tablets */
@media (max-width: 991.98px) {
#title-page {
padding-top: 90px;
}
#item-module {
margin-bottom: 5px;
}
h1{
font-size: 14px;
}
.card {
width: 100%;
height: auto;
}
.card-text {
font-size: 18px;
text-align: right;
width: 100%;
}
.card-bdy {
text-align: right;
}
}

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MenuEcosistemaComponent } from './menu-ecosistema.component';
describe('MenuEcosistemaComponent', () => {
let component: MenuEcosistemaComponent;
let fixture: ComponentFixture<MenuEcosistemaComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MenuEcosistemaComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MenuEcosistemaComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,63 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../auth/services/auth.service';
import { ModuleSystem } from '../models/module.model';
@Component({
selector: 'app-menu-ecosistema',
templateUrl: './menu-ecosistema.component.html',
styleUrls: ['./menu-ecosistema.component.scss']
})
export class MenuEcosistemaComponent implements OnInit {
modules: ModuleSystem[];
moduleSale: boolean = true;
modulePartner: boolean = true;
moduleAdmin = true;
constructor(
private readonly router: Router,
private readonly authService: AuthService) { }
ngOnInit(): void {
this.authService.getModules(this.authService.getUser())
.subscribe(m => {
this.modules = m;
this.modulesUser();
});
}
modulesUser() {
console.log(JSON.stringify(this.modules));
let module = this.modules.find(m => m.moduleId == 1) ;
if ( module === null ){
this.moduleSale = false;
} else {
console.log(JSON.stringify(module));
this.moduleSale = module.access == "S";
}
module = this.modules.find(m => m.moduleId == 2) ;
if ( module === undefined ){
this.modulePartner = false;
} else {
console.log(JSON.stringify(module));
this.modulePartner = module.access == "S";
}
module = this.modules.find(m => m.moduleId == 3) ;
this.moduleAdmin = false;
if ( module === undefined || module == null ){
this.moduleAdmin = false;
} else {
console.log(JSON.stringify(module));
this.moduleAdmin = module.access == "S";
}
}
openModule(url: string) {
this.router.navigate([url]);
// window.open(url, '_blank');
}
}

View File

@@ -0,0 +1,167 @@
<!--Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
<div class="container-fluid">
<!-- offcanvas trigger-->
<button
class="navbar-toggler"
type="button"
data-bs-toggle="offcanvas"
data-bs-target="#offcanvasExample"
aria-controls="offcanvasExample"
>
<span
class="navbar-toggler-icon"
data-bs-target="#offcanvasExample"
></span>
</button>
<!-- offcanvas trigger-->
<a class="navbar-brand" style="height: 40px; width: 120px" href="#">
<img src="assets/img/logo.svg" alt="" />
</a>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<form class="d-flex ms-auto">
<div class="input-group my-3 my-lg-0">
<input
class="form-control me-2"
type="search"
placeholder="Search"
aria-label="Search"
/>
<button class="btn btn-outline-success" type="submit">Search</button>
</div>
</form>
<ul class="navbar-nav mb-2 mb-lg-0">
<li class="nav-item dropdown">
<a
class="nav-link dropdown-toggle"
href="#"
id="navbarDropdown"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<i class="bi bi-person-fill"></i>
</a>
<ul
class="dropdown-menu dropdown-menu-end"
aria-labelledby="navbarDropdown"
>
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><hr class="dropdown-divider" /></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<!-- Navbar -->
<!-- OffCanvas -->
<div
class="offcanvas offcanvas-start sidebar-nav bg-dark text-light"
data-bs-backdrop="false"
data-bs-scroll="true"
tabindex="-1"
id="offcanvasExample"
aria-labelledby="offcanvasExampleLabel"
>
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasExampleLabel">Módulo de vendas</h5>
</div>
<div class="offcanvas-body">
<ul class="navbar-nav">
<li class="nav-item">
<a
class="nav-link px-3 sidebar-link"
>
<span><i class="bi bi-graph-up-arrow me-2"></i></span>
<span>Dashboard</span>
</a>
</li>
<li class="nav-item">
<a
class="nav-link px-3 sidebar-link"
data-bs-toggle="collapse"
href="#collapseExample"
role="button"
aria-expanded="false"
aria-controls="collapseExample"
>
<span><i class="bi bi-shop me-2"></i></span>
<span>Vendas</span>
<span class="right-icon ms-auto"
><i class="bi bi-chevron-down"></i
></span>
</a>
<div class="collapse" id="collapseExample">
<div>
<ul class="navbar-nav ps-3">
<li>
<a href="#" class="nav-link px-3">
<span>Pedidos de venda</span>
</a>
</li>
</ul>
</div>
</div>
</li>
<li>
<ul class="navbar-nav">
<li class="nav-item">
<a
class="nav-link px-3 sidebar-link"
data-bs-toggle="collapse"
href="#collapseregister"
role="button"
aria-expanded="false"
aria-controls="collapseregister"
>
<span><i class="bi bi-person-plus me-2"></i></span>
<span>Cadastros</span>
<span class="right-icon ms-auto"
><i class="bi bi-chevron-down"></i
></span>
</a>
<div class="collapse" id="collapseregister">
<div>
<ul class="navbar-nav ps-3">
<li>
<a href="#" class="nav-link px-3">
<span>Clientes</span>
</a>
</li>
</ul>
</div>
</div>
</li>
</ul>
</li>
</ul>
</div>
</div>
<!-- OffCanvas -->
<main class="mt-5 pt-3">
<div class="container-fluid">
<span>teste</span>
<router-outlet></router-outlet>
</div>
</main>

View File

@@ -0,0 +1,61 @@
.navbar {
background-color: rgba(28, 30, 84, 1);
}
#menu-vertical{
position:fixed;
z-index:999;
overflow:hidden;
padding:6px;
height: 100vh;
}
:root {
--offcanvas-width: 270px;
--topNavbarHeight: 56px;
}
.sidebar-nav {
width: 270px;
}
.sidebar-link {
display: flex;
align-items: center;
}
.sidebar-link .right-icon {
display: inline-flex;
transition: all ease 0.25s;
}
.sidebar-link[aria-expanded="true"] .right-icon {
transform: rotate(180deg);
}
li a {
text-decoration: none;
color: white;
}
@media (min-width: 992px) {
body {
overflow: auto !important;
}
main {
margin-left: 270px;
}
.offcanvas-backdrop::before{
display: none;
}
.sidebar-nav{
transform: none;
visibility: visible !important;
top: 56px;
height: calc(100% - 56px);
}
}

View File

@@ -0,0 +1,28 @@
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { MenuComponent } from './menu.component';
describe('MenuComponent', () => {
let component: MenuComponent;
let fixture: ComponentFixture<MenuComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MenuComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MenuComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.scss']
})
export class MenuComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@@ -0,0 +1,8 @@
export class ActionsUser {
moduleId: number;
processId: number;
pageId: number;
actionId: number;
userId: number;
access: string;
}

View File

@@ -0,0 +1,4 @@
export interface AuthUser {
email: string;
password: string;
}

View File

@@ -0,0 +1,90 @@
export interface Billing {
codcob: string;
cobranca: string;
pagcomissao: string;
txjuros: number;
codmoeda: string;
baixacxbanco: string;
nivelvenda: number;
fluxocx: string;
colunafluxocx: number;
numdiasvencfluxocx: number;
bloqautomatico: string;
numdiasbloqautomatic?: any;
exibircxmot: string;
exibirbk: string;
percacresvenda: number;
prazomaximovenda: number;
letracob?: any;
boleto: string;
custodia: string;
permitealtcobdesd: string;
percom: number;
vltarifa?: any;
codecf?: any;
cartao: string;
obsnf?: any;
numdiasliberacaocredito?: any;
codclicc: number;
prazocc: number;
perctxadmincc: number;
codcontacc: number;
codcobcc: string;
enviacobrancafv: string;
validalimcredecf: string;
diascarencia: number;
acertoautocxmot: string;
codparaprotesto: string;
envioparaprotesto: string;
numdiasprotesto: string;
numbanco?: any;
permitedescdevcli: string;
percommot?: any;
cobrancabroker: string;
vlminpedido?: any;
depositobancario: string;
tipocomissao: string;
codbancotarifa?: any;
codfilial?: any;
exportarecf: string;
codbanco?: any;
somatarifabancduplic?: any;
somatarifabancnf?: any;
codoperadoracartao: string;
tipooperacaotef: string;
tipopagtoecf: string;
nummaxparcelas?: any;
codparanaoprotesto?: any;
permitebaixamanual: string;
numviascpadicional: string;
codbandeira: number;
selecionaclienteecf: string;
autenticaracertocx402: string;
utilizachdesc?: any;
codcobchdesc?: any;
codcobdevchdesc?: any;
permitecontravale: string;
cobrancaemtransito: string;
calcjuroscobranca: string;
codigobandeira?: any;
convenio?: any;
recargacelular: string;
codrede?: any;
txprimeiraparcela: string;
naovalidaprazomedio?: any;
cheque: string;
flexivel: string;
codcobsefaz: string;
codbandeiraoperadoracartao: string;
bandeiracartao?: any;
percmulta: number;
cobsuppliercard: string;
indpag: number;
dtmxsalter: Date;
mxdiasinad?: any;
mxinad?: any;
codoutro?: any;
carteiradigital?: any;
nomecarteiradigital?: any;
descricaoformapagto?: any;
}

View File

@@ -0,0 +1,4 @@
export class BrandFilter {
description: string;
checked: boolean;
}

View File

@@ -0,0 +1,9 @@
export class CalculatePriceColor {
storeId: string;
productId: number;
letter: string;
line: string;
can: number;
color: string;
price: number;
}

View File

@@ -0,0 +1,12 @@
export class CartItensModel {
idProduct: number;
ean: number;
idStock: string;
deliveryMethod: string;
quantity: number;
listPrice: number;
salePrice: number;
descriptionAux: string;
environment?: string;
}

View File

@@ -0,0 +1,29 @@
import { CartItensModel } from './cart-itens.model';
export class CartModel {
id: string;
saleStore: string;
userId: number;
idCustomer: number;
idSeller: number;
idProfessional: number;
idPaymentPlan: number;
idBilling: string;
shippingDate: Date;
scheduleDelivery: boolean;
shippingValue: number;
notation1: string;
notation2: string;
notation3: string;
idAddress: number;
deliveryNote1: string;
deliveryNote2: string;
deliveryNote3: string;
shippingPriority: string;
idStorePlace?: number;
preCustomerDocument: string;
preCustomerName: string;
preCustomerPhone: string;
carrierId: number;
itens: CartItensModel[];
}

View File

@@ -0,0 +1,6 @@
export class CategoryPartner {
id: number;
partnerType: string;
name: string;
paymentType: string;
}

Some files were not shown because too many files have changed in this diff Show More