mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Compare commits
12 Commits
feature/52
...
feature/47
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58b0fde3f8 | ||
|
|
22b0c57fb0 | ||
|
|
e59ddaf6a6 | ||
|
|
a74b4ed791 | ||
|
|
3017f341af | ||
|
|
c75a6d87f9 | ||
|
|
b85b69f078 | ||
|
|
93c050f09a | ||
|
|
23b2a05d47 | ||
|
|
bd746f9915 | ||
|
|
91f70b0503 | ||
|
|
3237dff1bc |
@@ -2,3 +2,6 @@ last 1 Chrome version
|
||||
last 1 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 iOS major versions
|
||||
safari > 11
|
||||
Firefox ESR
|
||||
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
||||
@@ -7,7 +7,6 @@ indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = crlf
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
|
||||
86
.github/commit-instructions.md
vendored
86
.github/commit-instructions.md
vendored
@@ -1,86 +0,0 @@
|
||||
# Commit Message Instructions (Conventional Commits)
|
||||
|
||||
Commit messages should follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/). This provides a standardized format for commit messages, making it easier to understand changes, automate changelog generation, and trigger build/publish processes.
|
||||
|
||||
## Format
|
||||
|
||||
The commit message structure is as follows:
|
||||
|
||||
```
|
||||
<type>[optional scope]: <description>
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Components
|
||||
|
||||
1. **Type**: Indicates the kind of change introduced by the commit. Must be one of the allowed types (see below).
|
||||
2. **Scope (Optional)**: A noun describing the section of the codebase affected by the change (e.g., `auth`, `ui`, `build`). Enclosed in parentheses.
|
||||
3. **Description**: A concise summary of the change in the imperative, present tense (e.g., "add login feature", not "added login feature" or "adds login feature"). Starts with a lowercase letter and should not end with a period. Max 72 characters recommended for the entire header line (`<type>[optional scope]: <description>`).
|
||||
4. **Body (Optional)**: A more detailed explanation of the changes. Use the imperative, present tense. Explain the _what_ and _why_ vs. _how_. Separate from the description by a blank line. Wrap lines at 72 characters.
|
||||
5. **Footer(s) (Optional)**: Contains additional metadata. Common footers include:
|
||||
- `BREAKING CHANGE:` followed by a description of the breaking change. A `!` can also be appended to the type/scope (`feat!:`) to indicate a breaking change.
|
||||
- Issue references (e.g., `Refs: #123`, `Closes: #456`). Separate from the body by a blank line.
|
||||
|
||||
---
|
||||
|
||||
### Allowed Types
|
||||
|
||||
- **feat**: A new feature for the user.
|
||||
- **fix**: A bug fix for the user.
|
||||
- **build**: Changes that affect the build system or external dependencies (e.g., gulp, broccoli, npm).
|
||||
- **chore**: Other changes that don't modify src or test files (e.g., updating dependencies, build tasks).
|
||||
- **ci**: Changes to CI configuration files and scripts (e.g., Travis, Circle, BrowserStack, SauceLabs).
|
||||
- **docs**: Documentation only changes.
|
||||
- **perf**: A code change that improves performance.
|
||||
- **refactor**: A code change that neither fixes a bug nor adds a feature.
|
||||
- **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc).
|
||||
- **test**: Adding missing tests or correcting existing tests.
|
||||
|
||||
---
|
||||
|
||||
### Examples
|
||||
|
||||
**Commit with description only:**
|
||||
|
||||
```
|
||||
fix: correct minor typos in code
|
||||
```
|
||||
|
||||
**Commit with scope:**
|
||||
|
||||
```
|
||||
feat(lang): add polish language
|
||||
```
|
||||
|
||||
**Commit with body and breaking change footer:**
|
||||
|
||||
```
|
||||
refactor: drop support for Node 6
|
||||
|
||||
The new implementation relies on async/await and other features
|
||||
introduced in Node 8+.
|
||||
|
||||
BREAKING CHANGE: refactor to use JavaScript features not available in Node 6.
|
||||
```
|
||||
|
||||
**Commit with scope, body, and issue footer:**
|
||||
|
||||
```
|
||||
docs(readme): improve installation instructions
|
||||
|
||||
Provide clearer steps for setting up the development environment.
|
||||
Add links to prerequisite tools.
|
||||
|
||||
Closes: #12
|
||||
```
|
||||
|
||||
**Commit with `!` for breaking change:**
|
||||
|
||||
```
|
||||
feat(api)!: send an email to the customer when a product is shipped
|
||||
```
|
||||
23
.github/copilot-instructions.md
vendored
23
.github/copilot-instructions.md
vendored
@@ -1,23 +0,0 @@
|
||||
# Mentor Instructions
|
||||
|
||||
## Introduction
|
||||
|
||||
You are Mentor, an AI assistant focused on ensuring code quality, strict adherence to best practices, and development efficiency. **Your core function is to enforce the coding standards and guidelines established in this workspace.** Your goal is to help me produce professional, maintainable, and high-performing code.
|
||||
|
||||
**Always get the latest official documentation for Angular, Nx, or any related technology before implementing or when answering questions or providing feedback. Use Context7:**
|
||||
|
||||
## Tone and Personality
|
||||
|
||||
Maintain a professional, objective, and direct tone consistently:
|
||||
|
||||
- **Guideline Enforcement & Error Correction:** When code deviates from guidelines or contains errors, provide precise, technical feedback. Clearly state the issue, cite the relevant guideline or principle, and explain the required correction for optimal, maintainable results.
|
||||
- **Technical Consultation:** In discussions about architecture, best practices, or complex coding inquiries, remain formal and analytical. Provide clear, well-reasoned explanations and recommendations grounded in industry standards and the project's specific guidelines.
|
||||
|
||||
## Behavioral Guidelines
|
||||
|
||||
- **Actionable Feedback:** Prioritize constructive, actionable feedback aimed at improving code quality, maintainability, and adherence to standards. Avoid rewriting code; focus on explaining the necessary changes and their rationale based on guidelines.
|
||||
- **Strict Guideline Adherence:** Base _all_ feedback, suggestions, and explanations rigorously on the guidelines documented within this workspace. Cite specific rules and principles consistently.
|
||||
- **Demand Clarity:** If a query or code snippet lacks sufficient detail for a thorough, professional analysis, request clarification.
|
||||
- **Professional Framing:** Frame all feedback objectively, focusing on the technical aspects and the importance of meeting project standards for long-term success.
|
||||
- **Context-Specific Expertise:** Provide specific, context-aware advice tailored to the code or problem, always within the framework of our established guidelines.
|
||||
- **Enforce Standards:** Actively enforce project preferences for Type safety, Clean Code principles, and thorough documentation, as mandated by the workspace guidelines.
|
||||
182
.github/review-instructions.md
vendored
182
.github/review-instructions.md
vendored
@@ -1,182 +0,0 @@
|
||||
# Code Review Instructions
|
||||
|
||||
## Summary
|
||||
|
||||
When conducting a code review, follow these steps to ensure a thorough and constructive process.
|
||||
**Ensure that all review guidelines are followed. If any guideline is not adhered to, make it explicitly clear which guideline needs to be followed.**
|
||||
|
||||
## Review Process
|
||||
|
||||
1. 🎯 **Key Issues**
|
||||
Identify critical issues in the code such as bugs, security vulnerabilities, or violations of the project's coding standards.
|
||||
_Include specific links to files and line numbers (e.g., file.js#L10) where applicable._
|
||||
|
||||
2. 💡 **Suggestions for Improvement**
|
||||
Highlight areas where the code can be enhanced in terms of readability, performance, maintainability, or adherence to best practices.
|
||||
_Clarify what constitutes a "Critical" versus a "Minor" issue to avoid ambiguity._
|
||||
|
||||
3. ✨ **Code Examples**
|
||||
Provide specific, concise code snippets that illustrate your suggestions.
|
||||
_Include both a "Before" (problematic code) and an "After" (improved version) example where beneficial._
|
||||
|
||||
4. 📚 **Relevant Documentation Links**
|
||||
Attach links to useful resources or official documentation to support the suggested changes.
|
||||
_For example, link to ESLint, Jest, or Angular Style Guide pages when relevant._
|
||||
|
||||
## Tone and Feedback
|
||||
|
||||
- Be constructive and supportive.
|
||||
Frame suggestions as opportunities for growth rather than criticism.
|
||||
- Use the following emojis to categorize your feedback:
|
||||
- 🚨 **Critical issues**
|
||||
- ❗ **Minor Issues**
|
||||
- ⚠️ **Warnings**
|
||||
- 💡 **Suggestions**
|
||||
- ✅ **Good practices**
|
||||
|
||||
## Additional Informations
|
||||
|
||||
- Missing tests and JSDocs are minor issues
|
||||
- Missing unit test are minor issues
|
||||
- Missing End-to-End (E2E) Testing Attributes (`data-what`, `data-which`) are warnings
|
||||
|
||||
### Review Template
|
||||
|
||||
````markdown
|
||||
# Code Review
|
||||
|
||||
## Summary
|
||||
|
||||
A brief overview of the code’s overall quality, highlighting key strengths and areas needing attention. This sets the stage for the detailed feedback below.
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Critical Issues
|
||||
|
||||
High-priority issues that must be addressed immediately due to their potential to severely impact functionality, performance, or security.
|
||||
|
||||
### 1. High Priority: [Issue Title]
|
||||
|
||||
#### 🚨 Issue
|
||||
|
||||
Describe the issue clearly, including links to specific files and lines (e.g., file.js#L10). Explain why it’s critical—highlight crashes, security risks, or significant performance issues.
|
||||
|
||||
#### 💡 Suggestions for Improvement
|
||||
|
||||
Provide specific steps or alternative approaches to resolve the issue.
|
||||
|
||||
#### ✨ Code Example
|
||||
|
||||
**Current**: [file](file.js#L10) Problematic code with path to the file and line of the code
|
||||
|
||||
```typescript
|
||||
// Code...
|
||||
```
|
||||
|
||||
**Improvement**: Improved version
|
||||
|
||||
```typescript
|
||||
// Code...
|
||||
```
|
||||
|
||||
#### 📚 Relevant Documentation
|
||||
|
||||
Include URLs for further research (e.g., [Jest Documentation](https://jestjs.io/docs/getting-started)).
|
||||
|
||||
---
|
||||
|
||||
## ❗ Minor Issues
|
||||
|
||||
Issues that can improve code quality, maintainability, or adherence to best practices when resolved.
|
||||
|
||||
### 1. Medium Priority: [Issue Title]
|
||||
|
||||
#### ❗ Issue
|
||||
|
||||
Describe the issue clearly, including file and line references (e.g., file.js#L10). Explain the impact on the project.
|
||||
|
||||
#### 💡 Suggestions for Improvement
|
||||
|
||||
Offer concrete steps or alternative approaches to mitigate the issue.
|
||||
|
||||
#### ✨ Code Example
|
||||
|
||||
**Current**: [file](file.js#L10) Problematic code with path to the file and line of the code
|
||||
|
||||
```typescript
|
||||
// Code...
|
||||
```
|
||||
|
||||
**Improvement**: Improved version
|
||||
|
||||
```typescript
|
||||
// Code...
|
||||
```
|
||||
|
||||
#### 📚 Relevant Documentation
|
||||
|
||||
Provide links to further resources.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Warnings
|
||||
|
||||
Low-priority issues or suggestions that could help prevent future problems or improve the code quality over time.
|
||||
|
||||
### 1. Low Priority: [Issue Title]
|
||||
|
||||
#### ⚠️ Issue
|
||||
|
||||
Describe the issue clearly with references (e.g., file.js#L10). Explain the potential impact if left unaddressed.
|
||||
|
||||
#### 💡 Suggestions for Improvement
|
||||
|
||||
Provide suggestions or alternative implementations to mitigate the issue.
|
||||
|
||||
#### ✨ Code Example
|
||||
|
||||
**Current**: [file](file.js#L10) Problematic code with path to the file and line of the code
|
||||
|
||||
```typescript
|
||||
// Code...
|
||||
```
|
||||
|
||||
**Improvement**: Improved version
|
||||
|
||||
```typescript
|
||||
// Code...
|
||||
```
|
||||
|
||||
#### 📚 Relevant Documentation
|
||||
|
||||
Include relevant resources for more information.
|
||||
|
||||
---
|
||||
|
||||
## 🛑 Bad Practices
|
||||
|
||||
Highlight up to five bad aspects of the code to reinforce improvements and encourage good practices. Use different funny emoji at the beginning of each bad practice.
|
||||
|
||||
- Emoji **Bad Practice 1**:
|
||||
Describe a specific weakness (e.g., clear code structure) with an example reference (e.g., file.js#L20). Explain why it’s bad.
|
||||
- Emoji **Bad Practice 2**:
|
||||
Outline another negative feature (e.g., effective error handling) with a snippet reference.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Good Practices
|
||||
|
||||
Highlight up to five positive aspects of the code to reinforce well-implemented patterns and encourage good practices. Use different funny emoji at the beginning of each good practice.
|
||||
|
||||
- Emoji **Good Practice 1**:
|
||||
Describe a specific strength (e.g., clear code structure) with an example reference (e.g., file.js#L20). Explain why it’s commendable.
|
||||
- Emoji **Good Practice 2**:
|
||||
Outline another positive feature (e.g., effective error handling) with a snippet reference.
|
||||
|
||||
---
|
||||
|
||||
## 📓 Additional Notes
|
||||
|
||||
- **General Feedback**: Optional thoughts regarding the overall quality or potential areas for future improvement.
|
||||
- **Next Steps**: Outline follow-up actions or further examination areas as needed.
|
||||
````
|
||||
73
.github/testing-instructions.md
vendored
73
.github/testing-instructions.md
vendored
@@ -1,73 +0,0 @@
|
||||
# Testing Instructions
|
||||
|
||||
## Framework and Tools
|
||||
|
||||
- **Vitest** is the recommended testing framework.
|
||||
[Vitest Documentation (latest)](https://context7.com/vitest-dev/vitest/llms.txt?topic=getting+started)
|
||||
- **Jest** and **Spectator** are **deprecated**.
|
||||
Do not use them for new tests. Existing tests should be migrated to Vitest where possible.
|
||||
|
||||
## Guidelines
|
||||
|
||||
1. **Error Case Testing**: Ensure all edge cases and error scenarios are thoroughly tested.
|
||||
2. **Arrange-Act-Assert Pattern**: Follow the Arrange-Act-Assert pattern for structuring your tests:
|
||||
- **Arrange**: Set up the testing environment and initialize required variables.
|
||||
- **Act**: Execute the functionality being tested.
|
||||
- **Assert**: Verify the expected outcomes.
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Write clear and descriptive test names.
|
||||
- Ensure tests are isolated and do not depend on each other.
|
||||
- Mock external dependencies to avoid side effects.
|
||||
- Aim for high code coverage without compromising test quality.
|
||||
|
||||
## Example Test Structure
|
||||
|
||||
```typescript
|
||||
// Example using Vitest (Jest and Spectator are deprecated)
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { render } from '@testing-library/angular';
|
||||
import { MyComponent } from './my-component.component';
|
||||
|
||||
describe('MyComponent', () => {
|
||||
let component: MyComponent;
|
||||
|
||||
beforeEach(async () => {
|
||||
const { fixture } = await render(MyComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should display the correct title', async () => {
|
||||
// Arrange
|
||||
const expectedTitle = 'Hello World';
|
||||
|
||||
// Act
|
||||
component.title = expectedTitle;
|
||||
// If using Angular, trigger change detection:
|
||||
// fixture.detectChanges();
|
||||
|
||||
// Assert
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('h1')?.textContent).toBe(expectedTitle);
|
||||
});
|
||||
|
||||
it('should handle error cases gracefully', () => {
|
||||
// Arrange
|
||||
const invalidInput = null;
|
||||
|
||||
// Act
|
||||
component.input = invalidInput;
|
||||
|
||||
// Assert
|
||||
expect(() => component.processInput()).toThrowError('Invalid input');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Vitest Documentation (latest)](https://context7.com/vitest-dev/vitest/llms.txt?topic=getting+started)
|
||||
- [Vitest Official Guide](https://vitest.dev/guide/)
|
||||
- [Testing Library for Angular](https://testing-library.com/docs/angular-testing-library/intro/)
|
||||
- **Jest** and **Spectator** documentation are deprecated
|
||||
127
.gitignore
vendored
127
.gitignore
vendored
@@ -1,77 +1,50 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
.matomo
|
||||
junit.xml
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
/
|
||||
|
||||
# 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
|
||||
/.angular/cache
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/testresults
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
yarn.lock
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
libs/swagger/src/lib/*
|
||||
*storybook.log
|
||||
|
||||
|
||||
.nx/cache
|
||||
.nx/workspace-data
|
||||
.angular
|
||||
.claude
|
||||
|
||||
|
||||
storybook-static
|
||||
|
||||
.cursor\rules\nx-rules.mdc
|
||||
.github\instructions\nx.instructions.md
|
||||
.cursor/rules/nx-rules.mdc
|
||||
.github/instructions/nx.instructions.md
|
||||
|
||||
vite.config.*.timestamp*
|
||||
vitest.config.*.timestamp*
|
||||
|
||||
.mcp.json
|
||||
.memory.json
|
||||
|
||||
nx.instructions.md
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# profiling files
|
||||
chrome-profiler-events.json
|
||||
speed-measure-plugin.json
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
.prettierrc
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# misc
|
||||
/.angular/cache
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/testresults
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
yarn.lock
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
libs/swagger/src/lib/*
|
||||
@@ -1 +1 @@
|
||||
npx lint-staged
|
||||
npm run pretty-quick
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"*.ts": "npx eslint --fix --config eslint.config.js",
|
||||
"*.tsx": "npx eslint --fix --config eslint.config.js",
|
||||
"*.js": "npx eslint --fix --config eslint.config.js",
|
||||
"*.jsx": "npx eslint --fix --config eslint.config.js",
|
||||
"*.html": "npx eslint --fix --config eslint.config.js"
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
# Add files here to ignore them from prettier formatting
|
||||
|
||||
/dist
|
||||
/coverage
|
||||
/.nx/cache
|
||||
/.nx/workspace-data
|
||||
/node_modules
|
||||
.angular
|
||||
.vscode
|
||||
/helmvalues
|
||||
/apps/swagger
|
||||
/ng-swagger-gen
|
||||
|
||||
*.json
|
||||
*.yml
|
||||
|
||||
37
.prettierrc
37
.prettierrc
@@ -1,37 +0,0 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"semi": true,
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 2,
|
||||
"bracketSpacing": true,
|
||||
"printWidth": 80,
|
||||
"endOfLine": "auto",
|
||||
"arrowParens": "always",
|
||||
"quoteProps": "consistent",
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.html",
|
||||
"options": {
|
||||
"parser": "html"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.component.html",
|
||||
"options": {
|
||||
"parser": "angular"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.scss",
|
||||
"options": {
|
||||
"singleQuote": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.json",
|
||||
"options": {
|
||||
"printWidth": 80
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
5
.prettierrc.json
Normal file
5
.prettierrc.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"printWidth": 140
|
||||
}
|
||||
|
||||
16
.vscode/extensions.json
vendored
16
.vscode/extensions.json
vendored
@@ -1,11 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"johnpapa.angular2",
|
||||
"esbenp.prettier-vscode",
|
||||
"angular.ng-template",
|
||||
"nrwl.angular-console",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"firsttris.vscode-jest-runner",
|
||||
"editorconfig.editorconfig"
|
||||
]
|
||||
}
|
||||
"recommendations": [
|
||||
"johnpapa.angular2",
|
||||
"esbenp.prettier-vscode",
|
||||
"angular.ng-template",
|
||||
]
|
||||
}
|
||||
87
.vscode/settings.json
vendored
87
.vscode/settings.json
vendored
@@ -1,92 +1,15 @@
|
||||
{
|
||||
"editor.accessibilitySupport": "off",
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"exportall.config.exclude": [".test.", ".spec.", ".stories."],
|
||||
"editor.formatOnSave": true,
|
||||
"typescriptHero.imports.insertSemicolons": false,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"eslint.validate": [
|
||||
"json"
|
||||
],
|
||||
"[html]": {
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"exportall.config.folderListener": [
|
||||
"/libs/oms/data-access/src/lib/models",
|
||||
"/libs/oms/data-access/src/lib/schemas",
|
||||
"/libs/catalogue/data-access/src/lib/models",
|
||||
"/libs/common/data-access/src/lib/models",
|
||||
"/libs/common/data-access/src/lib/error",
|
||||
"/libs/oms/data-access/src/lib/errors/return-process"
|
||||
],
|
||||
"github.copilot.chat.commitMessageGeneration.instructions": [
|
||||
{
|
||||
"file": ".github/commit-instructions.md"
|
||||
}
|
||||
],
|
||||
"github.copilot.chat.codeGeneration.instructions": [
|
||||
{
|
||||
"file": ".vscode/llms/angular.txt"
|
||||
},
|
||||
{
|
||||
"file": "docs/tech-stack.md"
|
||||
},
|
||||
{
|
||||
"file": "docs/guidelines/code-style.md"
|
||||
},
|
||||
{
|
||||
"file": "docs/guidelines/project-structure.md"
|
||||
},
|
||||
{
|
||||
"file": "docs/guidelines/state-management.md"
|
||||
},
|
||||
{
|
||||
"file": "docs/guidelines/testing.md"
|
||||
}
|
||||
],
|
||||
"github.copilot.chat.testGeneration.instructions": [
|
||||
{
|
||||
"file": ".github/testing-instructions.md"
|
||||
},
|
||||
{
|
||||
"file": "docs/tech-stack.md"
|
||||
},
|
||||
{
|
||||
"file": "docs/guidelines/code-style.md"
|
||||
},
|
||||
{
|
||||
"file": "docs/guidelines/testing.md"
|
||||
}
|
||||
],
|
||||
"github.copilot.chat.reviewSelection.instructions": [
|
||||
{
|
||||
"file": ".github/copilot-instructions.md"
|
||||
},
|
||||
{
|
||||
"file": ".github/review-instructions.md"
|
||||
},
|
||||
{
|
||||
"file": "docs/tech-stack.md"
|
||||
},
|
||||
{
|
||||
"file": "docs/guidelines/code-style.md"
|
||||
},
|
||||
{
|
||||
"file": "docs/guidelines/project-structure.md"
|
||||
},
|
||||
{
|
||||
"file": "docs/guidelines/state-management.md"
|
||||
},
|
||||
{
|
||||
"file": "docs/guidelines/testing.md"
|
||||
}
|
||||
],
|
||||
"nxConsole.generateAiAgentRules": true,
|
||||
"chat.mcp.enabled": true,
|
||||
"chat.mcp.discovery.enabled": true
|
||||
"css.validate": false,
|
||||
"less.validate": false,
|
||||
"scss.validate": false
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#stage 1
|
||||
FROM node:22 as base
|
||||
FROM node:18 as base
|
||||
ARG IS_PRODUCTION=false
|
||||
ARG SEMVERSION=1.0.0
|
||||
ARG BuildUniqueID
|
||||
@@ -8,7 +8,7 @@ WORKDIR /app
|
||||
COPY . .
|
||||
RUN umask 0022
|
||||
RUN npm version ${SEMVERSION}
|
||||
RUN npm install --foreground-scripts
|
||||
RUN npm install --always-auth=false
|
||||
RUN if [ "${IS_PRODUCTION}" = "true" ] ; then npm run-script build-prod ; else npm run-script build ; fi
|
||||
|
||||
# stage final
|
||||
@@ -24,6 +24,6 @@ ARG BuildUniqueID
|
||||
LABEL build.uniqueid="${BuildUniqueID:-1}"
|
||||
RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -q -O /tmp/chrome.deb && apt update && apt install -y /tmp/chrome.deb
|
||||
# ignore exitcode, sonst gibts keinen container
|
||||
RUN npm run ci || true
|
||||
RUN npm test || true
|
||||
ENTRYPOINT [ "/bin/sleep", "60000" ]
|
||||
|
||||
|
||||
135
angular.json
Normal file
135
angular.json
Normal file
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "apps",
|
||||
"projects": {
|
||||
"isa-app": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
},
|
||||
"@schematics/angular:application": {
|
||||
"strict": true
|
||||
}
|
||||
},
|
||||
"root": "apps/isa-app",
|
||||
"sourceRoot": "apps/isa-app/src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"allowedCommonJsDependencies": [
|
||||
"lodash",
|
||||
"moment",
|
||||
"jsrsasign",
|
||||
"pdfjs-dist/build/pdf",
|
||||
"pdfjs-dist/web/pdf_viewer",
|
||||
"pdfjs-dist/es5/build/pdf",
|
||||
"pdfjs-dist/es5/web/pdf_viewer",
|
||||
"scandit-sdk"
|
||||
],
|
||||
"outputPath": "dist/isa-app",
|
||||
"index": "apps/isa-app/src/index.html",
|
||||
"main": "apps/isa-app/src/main.ts",
|
||||
"polyfills": "apps/isa-app/src/polyfills.ts",
|
||||
"tsConfig": "apps/isa-app/tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"apps/isa-app/src/favicon.ico",
|
||||
"apps/isa-app/src/assets",
|
||||
"apps/isa-app/src/config",
|
||||
"apps/isa-app/src/silent-refresh.html",
|
||||
"apps/isa-app/src/manifest.webmanifest",
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "node_modules/scandit-sdk/build",
|
||||
"output": "scandit"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"apps/isa-app/src/styles.scss"
|
||||
],
|
||||
"scripts": [],
|
||||
"serviceWorker": true,
|
||||
"ngswConfigPath": "apps/isa-app/ngsw-config.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "25kb"
|
||||
}
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "apps/isa-app/src/environments/environment.ts",
|
||||
"with": "apps/isa-app/src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "isa-app:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "isa-app:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"buildTarget": "isa-app:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"tsConfig": "apps/isa-app/tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
],
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"apps/isa-app/src/favicon.ico",
|
||||
"apps/isa-app/src/assets",
|
||||
"apps/isa-app/src/manifest.webmanifest"
|
||||
],
|
||||
"styles": [
|
||||
"apps/isa-app/src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import type { StorybookConfig } from '@storybook/angular';
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ['../stories/**/*.@(mdx|stories.@(js|jsx|ts|tsx))'],
|
||||
addons: [
|
||||
'@storybook/addon-essentials',
|
||||
'@storybook/addon-interactions',
|
||||
'@storybook/addon-docs',
|
||||
],
|
||||
previewHead: (head) => `
|
||||
${head}
|
||||
<link href="/assets/fonts/fonts.css" rel="stylesheet" />
|
||||
`,
|
||||
framework: {
|
||||
name: '@storybook/angular',
|
||||
options: {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
// To customize your webpack configuration you can use the webpackFinal field.
|
||||
// Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config
|
||||
// and https://nx.dev/recipes/storybook/custom-builder-configs
|
||||
@@ -1,7 +0,0 @@
|
||||
import type { Preview } from '@storybook/angular';
|
||||
|
||||
const preview: Preview = {
|
||||
tags: ['autodocs'],
|
||||
};
|
||||
|
||||
export default preview;
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"emitDecoratorMetadata": true
|
||||
},
|
||||
"exclude": ["../**/*.spec.ts"],
|
||||
"include": [
|
||||
// "../src/**/*.stories.ts",
|
||||
// "../src/**/*.stories.js",
|
||||
// "../src/**/*.stories.jsx",
|
||||
// "../src/**/*.stories.tsx",
|
||||
// "../src/**/*.stories.mdx",
|
||||
"../stories/**/*.stories.ts",
|
||||
"../stories/**/*.stories.js",
|
||||
"../stories/**/*.stories.jsx",
|
||||
"../stories/**/*.stories.tsx",
|
||||
"../stories/**/*.stories.mdx",
|
||||
"*.js",
|
||||
"*.ts"
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,55 +0,0 @@
|
||||
const nx = require('@nx/eslint-plugin');
|
||||
const baseConfig = require('../../eslint.config.js');
|
||||
|
||||
module.exports = [
|
||||
...baseConfig,
|
||||
...nx.configs['flat/angular'],
|
||||
...nx.configs['flat/angular-template'],
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
rules: {
|
||||
'@angular-eslint/directive-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'attribute',
|
||||
prefix: 'app',
|
||||
style: 'camelCase',
|
||||
},
|
||||
],
|
||||
'@angular-eslint/component-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'element',
|
||||
prefix: 'app',
|
||||
style: 'kebab-case',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-unused-expressions': 'warn',
|
||||
'prefer-const': 'warn',
|
||||
'@angular-eslint/contextual-lifecycle': 'warn',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@angular-eslint/no-empty-lifecycle-method': 'warn',
|
||||
'@typescript-eslint/no-inferrable-types': 'warn',
|
||||
'@angular-eslint/component-selector': 'warn',
|
||||
'@angular-eslint/prefer-standalone': 'warn',
|
||||
'@typescript-eslint/no-inferrable-types': 'warn',
|
||||
'no-empty-function': 'warn',
|
||||
'@typescript-eslint/no-empty-function': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
'@angular-eslint/directive-selector': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.html'],
|
||||
// Override or add rules here
|
||||
rules: {
|
||||
'@angular-eslint/template/elements-content': 'warn',
|
||||
'@angular-eslint/template/no-autofocus': 'warn',
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -1,21 +0,0 @@
|
||||
export default {
|
||||
displayName: 'isa-app',
|
||||
preset: '../../jest.preset.js',
|
||||
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
|
||||
coverageDirectory: '../../coverage/apps/prj',
|
||||
transform: {
|
||||
'^.+\\.(ts|mjs|js|html)$': [
|
||||
'jest-preset-angular',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\.(html|svg)$',
|
||||
},
|
||||
],
|
||||
},
|
||||
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
|
||||
snapshotSerializers: [
|
||||
'jest-preset-angular/build/serializers/no-ng-attributes',
|
||||
'jest-preset-angular/build/serializers/ng-snapshot',
|
||||
'jest-preset-angular/build/serializers/html-comment',
|
||||
],
|
||||
};
|
||||
@@ -29,4 +29,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
{
|
||||
"name": "isa-app",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"projectType": "application",
|
||||
"prefix": "app",
|
||||
"sourceRoot": "apps/isa-app/src",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@angular-devkit/build-angular:application",
|
||||
"options": {
|
||||
"allowedCommonJsDependencies": [
|
||||
"lodash",
|
||||
"moment",
|
||||
"jsrsasign",
|
||||
"pdfjs-dist/build/pdf",
|
||||
"pdfjs-dist/web/pdf_viewer",
|
||||
"pdfjs-dist/es5/build/pdf",
|
||||
"pdfjs-dist/es5/web/pdf_viewer"
|
||||
],
|
||||
"outputPath": "dist/isa-app",
|
||||
"index": "apps/isa-app/src/index.html",
|
||||
"browser": "apps/isa-app/src/main.ts",
|
||||
"polyfills": ["zone.js"],
|
||||
"tsConfig": "apps/isa-app/tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"apps/isa-app/src/favicon.ico",
|
||||
"apps/isa-app/src/assets",
|
||||
"apps/isa-app/src/config",
|
||||
"apps/isa-app/src/silent-refresh.html",
|
||||
"apps/isa-app/src/manifest.webmanifest",
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "node_modules/scandit-web-datacapture-barcode/build/engine",
|
||||
"output": "scandit"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"@angular/cdk/overlay-prebuilt.css",
|
||||
"apps/isa-app/src/tailwind.scss",
|
||||
"apps/isa-app/src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "25kb"
|
||||
}
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "apps/isa-app/src/environments/environment.ts",
|
||||
"with": "apps/isa-app/src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all",
|
||||
"serviceWorker": "apps/isa-app/ngsw-config.json"
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production",
|
||||
"outputs": ["{options.outputPath}"]
|
||||
},
|
||||
"serve": {
|
||||
"executor": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "isa-app:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "isa-app:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development",
|
||||
"continuous": true
|
||||
},
|
||||
"extract-i18n": {
|
||||
"executor": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"buildTarget": "isa-app:build"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint"
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "apps/isa-app/jest.config.ts"
|
||||
}
|
||||
},
|
||||
"serve-static": {
|
||||
"executor": "@nx/web:file-server",
|
||||
"options": {
|
||||
"buildTarget": "isa-app:build",
|
||||
"staticFilePath": "dist/apps/isa-app/browser",
|
||||
"spa": true
|
||||
}
|
||||
},
|
||||
"storybook": {
|
||||
"executor": "@storybook/angular:start-storybook",
|
||||
"options": {
|
||||
"port": 4400,
|
||||
"configDir": "apps/isa-app/.storybook",
|
||||
"browserTarget": "isa-app:build",
|
||||
"compodoc": false,
|
||||
"open": false,
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/isa-app/src/assets",
|
||||
"output": "/assets"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"@angular/cdk/overlay-prebuilt.css",
|
||||
"apps/isa-app/src/tailwind.scss",
|
||||
"apps/isa-app/src/styles.scss"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"quiet": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"build-storybook": {
|
||||
"executor": "@storybook/angular:build-storybook",
|
||||
"outputs": ["{options.outputDir}"],
|
||||
"options": {
|
||||
"outputDir": "dist/storybook/isa-app",
|
||||
"configDir": "apps/isa-app/.storybook",
|
||||
"browserTarget": "isa-app:build",
|
||||
"compodoc": false,
|
||||
"styles": [
|
||||
"@angular/cdk/overlay-prebuilt.css",
|
||||
"apps/isa-app/src/tailwind.scss",
|
||||
"apps/isa-app/src/styles.scss"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"quiet": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,23 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import {
|
||||
PromptModalData,
|
||||
UiModalService,
|
||||
UiPromptModalComponent,
|
||||
} from '@ui/modal';
|
||||
import { Injectable, isDevMode } from '@angular/core';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { PromptModalData, UiModalService, UiPromptModalComponent } from '@ui/modal';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ScanAdapter } from './scan-adapter';
|
||||
import { Config } from '@core/config';
|
||||
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||
|
||||
@Injectable()
|
||||
export class DevScanAdapter implements ScanAdapter {
|
||||
readonly name = 'Dev';
|
||||
|
||||
private _modal = inject(UiModalService);
|
||||
|
||||
private _config = inject(Config);
|
||||
constructor(
|
||||
private _modal: UiModalService,
|
||||
private _environmentService: EnvironmentService,
|
||||
) {}
|
||||
|
||||
async init(): Promise<boolean> {
|
||||
const enabled = localStorage.getItem('dev_scan_adapter_enabled') === 'true';
|
||||
if (enabled) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(coerceBooleanProperty(this._config.get('dev-scanner')));
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
return Promise.resolve(false);
|
||||
// return new Promise((resolve, reject) => {
|
||||
// resolve(isDevMode());
|
||||
// });
|
||||
}
|
||||
|
||||
scan(): Observable<string> {
|
||||
@@ -34,8 +26,7 @@ export class DevScanAdapter implements ScanAdapter {
|
||||
content: UiPromptModalComponent,
|
||||
title: 'Scannen',
|
||||
data: {
|
||||
message:
|
||||
'Diese Eingabemaske dient nur zu Entwicklungs und Testzwecken.',
|
||||
message: 'Diese Eingabemaske dient nur zu Entwicklungs und Testzwecken.',
|
||||
placeholder: 'Scan Code',
|
||||
confirmText: 'weiter',
|
||||
cancelText: 'abbrechen',
|
||||
|
||||
@@ -4,10 +4,6 @@ import { Observable } from 'rxjs';
|
||||
import { filter, map, take } from 'rxjs/operators';
|
||||
import { ScanAdapter } from './scan-adapter';
|
||||
|
||||
/**
|
||||
* @deprecated This service will be removed in future versions.
|
||||
* Please use the new ScanService instead.
|
||||
*/
|
||||
@Injectable()
|
||||
export class NativeScanAdapter implements ScanAdapter {
|
||||
readonly name = 'Native';
|
||||
|
||||
@@ -37,7 +37,7 @@ export class ScanAdapterService {
|
||||
|
||||
for (const name of adapterOrder) {
|
||||
adapter = this.getAdapter(name);
|
||||
console.log('adapter', adapter);
|
||||
|
||||
if (adapter) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3,15 +3,12 @@
|
||||
}
|
||||
|
||||
.scanner-container {
|
||||
/* width: 100vw;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width: 100vh;
|
||||
max-height: 100vh; */
|
||||
}
|
||||
|
||||
.close-scanner {
|
||||
@apply absolute bottom-12 left-[50%] -translate-x-[50%] block px-6 py-4 bg-white text-brand border-2 border-solid border-brand rounded-full text-lg font-bold mx-auto mt-4;
|
||||
@apply whitespace-nowrap;
|
||||
}
|
||||
|
||||
@screen desktop {
|
||||
|
||||
@@ -1,27 +1,15 @@
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
ElementRef,
|
||||
ViewChild,
|
||||
NgZone,
|
||||
AfterViewInit,
|
||||
OnDestroy, OnInit,
|
||||
} from '@angular/core';
|
||||
import { BarcodeCapture, BarcodeCaptureSettings, Symbology } from 'scandit-web-datacapture-barcode';
|
||||
import { Camera, DataCaptureContext, DataCaptureView, FrameSourceState } from 'scandit-web-datacapture-core';
|
||||
import { Component, ChangeDetectionStrategy, ElementRef, ViewChild, NgZone, AfterViewInit, OnDestroy } from '@angular/core';
|
||||
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
import { Barcode, BarcodePicker, ScanResult, ScanSettings } from 'scandit-sdk';
|
||||
|
||||
@Component({
|
||||
selector: 'app-scandit-overlay',
|
||||
templateUrl: 'scandit-overlay.component.html',
|
||||
styleUrls: ['scandit-overlay.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: false,
|
||||
})
|
||||
export class ScanditOverlayComponent implements AfterViewInit, OnDestroy, OnInit {
|
||||
private dataCaptureContext: DataCaptureContext;
|
||||
private dataCaptureView: DataCaptureView;
|
||||
private barcodeCapture: BarcodeCapture;
|
||||
private camera: Camera;
|
||||
export class ScanditOverlayComponent implements AfterViewInit, OnDestroy {
|
||||
private _barcodePicker: BarcodePicker;
|
||||
|
||||
private _onScan?: (code: string) => void;
|
||||
|
||||
@@ -29,58 +17,57 @@ export class ScanditOverlayComponent implements AfterViewInit, OnDestroy, OnInit
|
||||
|
||||
@ViewChild('scanContainer', { read: ElementRef, static: true }) scanContainer: ElementRef;
|
||||
|
||||
constructor(private _zone: NgZone) {}
|
||||
constructor(
|
||||
private _zone: NgZone,
|
||||
private _modal: UiModalService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.dataCaptureView = new DataCaptureView();
|
||||
|
||||
this.dataCaptureView.connectToElement(this.scanContainer.nativeElement);
|
||||
|
||||
this.dataCaptureView.showProgressBar();
|
||||
ngAfterViewInit(): void {
|
||||
this.createBarcodePicker()
|
||||
.then(() => {
|
||||
this._barcodePicker.on('scan', (scanResult) => {
|
||||
this._zone.run(() => this.handleScanrResult(scanResult));
|
||||
});
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
this._modal
|
||||
.open({
|
||||
content: UiMessageModalComponent,
|
||||
title: 'Zugriff auf Kamera verweigert',
|
||||
data: { message: 'Falls Sie den Zugriff erlauben möchten, können Sie das über die Webseiteinstellung Ihres Browsers.' },
|
||||
})
|
||||
.afterClosed$.subscribe(() => {
|
||||
this._onClose?.();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async ngAfterViewInit() {
|
||||
this.dataCaptureContext = await DataCaptureContext.create();
|
||||
|
||||
this.dataCaptureView.setContext(this.dataCaptureContext);
|
||||
|
||||
this.barcodeCapture = await BarcodeCapture.forContext(this.dataCaptureContext, this.getScanSettings());
|
||||
|
||||
this.barcodeCapture.addListener({
|
||||
didScan: (_, session, __) => {
|
||||
this._zone.run(() => {
|
||||
const result = session.newlyRecognizedBarcode;
|
||||
|
||||
const code = result?.data ?? '';
|
||||
|
||||
this._onScan?.(code);
|
||||
});
|
||||
},
|
||||
async createBarcodePicker() {
|
||||
this._barcodePicker = await BarcodePicker.create(this.scanContainer.nativeElement, {
|
||||
playSoundOnScan: true,
|
||||
vibrateOnScan: true,
|
||||
});
|
||||
|
||||
this.camera = Camera.default;
|
||||
|
||||
this.dataCaptureContext.setFrameSource(this.camera);
|
||||
|
||||
await this.camera.switchToDesiredState(FrameSourceState.On);
|
||||
this.dataCaptureView.hideProgressBar();
|
||||
this._barcodePicker.applyScanSettings(this.getScanSettings());
|
||||
}
|
||||
|
||||
getScanSettings(): BarcodeCaptureSettings {
|
||||
const settings = new BarcodeCaptureSettings();
|
||||
getScanSettings(): ScanSettings {
|
||||
return new ScanSettings({
|
||||
blurryRecognition: false,
|
||||
|
||||
settings.enableSymbologies([
|
||||
Symbology.EAN8,
|
||||
Symbology.EAN13UPCA,
|
||||
Symbology.UPCE,
|
||||
Symbology.Code128,
|
||||
Symbology.Code39,
|
||||
Symbology.Code93,
|
||||
Symbology.InterleavedTwoOfFive,
|
||||
Symbology.QR,
|
||||
]);
|
||||
|
||||
return settings;
|
||||
enabledSymbologies: [
|
||||
Barcode.Symbology.EAN8,
|
||||
Barcode.Symbology.EAN13,
|
||||
Barcode.Symbology.UPCA,
|
||||
Barcode.Symbology.UPCE,
|
||||
Barcode.Symbology.CODE128,
|
||||
Barcode.Symbology.CODE39,
|
||||
Barcode.Symbology.CODE93,
|
||||
Barcode.Symbology.INTERLEAVED_2_OF_5,
|
||||
Barcode.Symbology.QR,
|
||||
],
|
||||
codeDuplicateFilter: 1000,
|
||||
});
|
||||
}
|
||||
|
||||
onScan(fn: (code: string) => void) {
|
||||
@@ -91,14 +78,26 @@ export class ScanditOverlayComponent implements AfterViewInit, OnDestroy, OnInit
|
||||
this._onClose = fn;
|
||||
}
|
||||
|
||||
handleScanrResult(scanRestul: ScanResult) {
|
||||
let result: string | undefined;
|
||||
if (scanRestul.barcodes.length) {
|
||||
result = scanRestul.barcodes[0].data;
|
||||
} else if (scanRestul.texts.length) {
|
||||
result = scanRestul.texts[0].value;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
this._onScan?.(result);
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
this._onClose?.();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this._zone.runOutsideAngular(() => {
|
||||
this.barcodeCapture?.setEnabled(false);
|
||||
this.camera?.switchToDesiredState(FrameSourceState.Off);
|
||||
this._barcodePicker?.destroy(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ import { Observable, Subscriber } from 'rxjs';
|
||||
import { ScanAdapter } from '../scan-adapter';
|
||||
import { Overlay } from '@angular/cdk/overlay';
|
||||
|
||||
import { configure } from 'scandit-web-datacapture-core';
|
||||
import { barcodeCaptureLoader } from 'scandit-web-datacapture-barcode';
|
||||
|
||||
import { configure } from 'scandit-sdk';
|
||||
// import { ScanditModalComponent } from './scandit-modal';
|
||||
import { Config } from '@core/config';
|
||||
import { ComponentPortal } from '@angular/cdk/portal';
|
||||
@@ -27,21 +25,12 @@ export class ScanditScanAdapter implements ScanAdapter {
|
||||
) {}
|
||||
|
||||
async init(): Promise<boolean> {
|
||||
const enabled =
|
||||
localStorage.getItem('scandit_scan_adapter_enabled') === 'true';
|
||||
if (this._environmentService.isTablet()) {
|
||||
await configure(this._config.get('licence.scandit'), {
|
||||
engineLocation: '/scandit/',
|
||||
});
|
||||
|
||||
if (enabled || this._environmentService.isTablet()) {
|
||||
try {
|
||||
await configure({
|
||||
licenseKey: this._config.get('licence.scandit'),
|
||||
libraryLocation: new URL('scandit', document.baseURI).toString(),
|
||||
moduleLoaders: [barcodeCaptureLoader()],
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('ScanditScanAdapter.init', error);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -91,11 +80,7 @@ export class ScanditScanAdapter implements ScanAdapter {
|
||||
|
||||
createOverlay() {
|
||||
const overlay = this._overlay.create({
|
||||
positionStrategy: this._overlay
|
||||
.position()
|
||||
.global()
|
||||
.centerHorizontally()
|
||||
.centerVertically(),
|
||||
positionStrategy: this._overlay.position().global().centerHorizontally().centerVertically(),
|
||||
hasBackdrop: true,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,231 +1,168 @@
|
||||
import { isDevMode, NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import {
|
||||
CanActivateCartGuard,
|
||||
CanActivateCartWithProcessIdGuard,
|
||||
CanActivateCustomerGuard,
|
||||
CanActivateCustomerOrdersGuard,
|
||||
CanActivateCustomerOrdersWithProcessIdGuard,
|
||||
CanActivateCustomerWithProcessIdGuard,
|
||||
CanActivateGoodsInGuard,
|
||||
CanActivateProductGuard,
|
||||
CanActivateProductWithProcessIdGuard,
|
||||
CanActivateRemissionGuard,
|
||||
CanActivateTaskCalendarGuard,
|
||||
IsAuthenticatedGuard,
|
||||
} from './guards';
|
||||
import { CanActivateAssortmentGuard } from './guards/can-activate-assortment.guard';
|
||||
import { CanActivatePackageInspectionGuard } from './guards/can-activate-package-inspection.guard';
|
||||
import { MainComponent } from './main.component';
|
||||
import { PreviewComponent } from './preview';
|
||||
import {
|
||||
BranchSectionResolver,
|
||||
CustomerSectionResolver,
|
||||
ProcessIdResolver,
|
||||
} from './resolvers';
|
||||
import { TokenLoginComponent, TokenLoginModule } from './token-login';
|
||||
import { ProcessIdGuard } from './guards/process-id.guard';
|
||||
import {
|
||||
ActivateProcessIdGuard,
|
||||
ActivateProcessIdWithConfigKeyGuard,
|
||||
} from './guards/activate-process-id.guard';
|
||||
import { MatomoRouteData } from 'ngx-matomo-client';
|
||||
import { tabResolverFn } from '@isa/core/tabs';
|
||||
import { provideScrollPositionRestoration } from '@isa/utils/scroll-position';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'kunde/dashboard', pathMatch: 'full' },
|
||||
{
|
||||
path: 'login',
|
||||
children: [
|
||||
{ path: ':token', component: TokenLoginComponent },
|
||||
{ path: '**', redirectTo: 'kunde', pathMatch: 'full' },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
canActivate: [IsAuthenticatedGuard],
|
||||
children: [
|
||||
{
|
||||
path: 'kunde',
|
||||
component: MainComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'dashboard',
|
||||
loadChildren: () =>
|
||||
import('@page/dashboard').then((m) => m.DashboardModule),
|
||||
data: {
|
||||
matomo: {
|
||||
title: 'Dashboard',
|
||||
} as MatomoRouteData,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'product',
|
||||
loadChildren: () =>
|
||||
import('@page/catalog').then((m) => m.PageCatalogModule),
|
||||
canActivate: [CanActivateProductGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/product',
|
||||
loadChildren: () =>
|
||||
import('@page/catalog').then((m) => m.PageCatalogModule),
|
||||
canActivate: [CanActivateProductWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'order',
|
||||
loadChildren: () =>
|
||||
import('@page/customer-order').then((m) => m.CustomerOrderModule),
|
||||
canActivate: [CanActivateCustomerOrdersGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/order',
|
||||
loadChildren: () =>
|
||||
import('@page/customer-order').then((m) => m.CustomerOrderModule),
|
||||
canActivate: [CanActivateCustomerOrdersWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'customer',
|
||||
loadChildren: () =>
|
||||
import('@page/customer').then((m) => m.CustomerModule),
|
||||
canActivate: [CanActivateCustomerGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/customer',
|
||||
loadChildren: () =>
|
||||
import('@page/customer').then((m) => m.CustomerModule),
|
||||
canActivate: [CanActivateCustomerWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'cart',
|
||||
loadChildren: () =>
|
||||
import('@page/checkout').then((m) => m.PageCheckoutModule),
|
||||
canActivate: [CanActivateCartGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/cart',
|
||||
loadChildren: () =>
|
||||
import('@page/checkout').then((m) => m.PageCheckoutModule),
|
||||
canActivate: [CanActivateCartWithProcessIdGuard],
|
||||
},
|
||||
{
|
||||
path: 'pickup-shelf',
|
||||
canActivate: [ProcessIdGuard],
|
||||
// NOTE: This is a workaround for the canActivate guard not being called
|
||||
loadChildren: () =>
|
||||
import('@page/pickup-shelf').then((m) => m.PickupShelfOutModule),
|
||||
},
|
||||
{
|
||||
path: ':processId/pickup-shelf',
|
||||
canActivate: [ActivateProcessIdGuard],
|
||||
loadChildren: () =>
|
||||
import('@page/pickup-shelf').then((m) => m.PickupShelfOutModule),
|
||||
},
|
||||
{ path: '**', redirectTo: 'dashboard', pathMatch: 'full' },
|
||||
],
|
||||
resolve: { section: CustomerSectionResolver },
|
||||
},
|
||||
{
|
||||
path: 'filiale',
|
||||
component: MainComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'task-calendar',
|
||||
loadChildren: () =>
|
||||
import('@page/task-calendar').then(
|
||||
(m) => m.PageTaskCalendarModule,
|
||||
),
|
||||
canActivate: [CanActivateTaskCalendarGuard],
|
||||
},
|
||||
{
|
||||
path: 'pickup-shelf',
|
||||
canActivate: [ActivateProcessIdWithConfigKeyGuard('pickupShelf')],
|
||||
// NOTE: This is a workaround for the canActivate guard not being called
|
||||
loadChildren: () =>
|
||||
import('@page/pickup-shelf').then((m) => m.PickupShelfInModule),
|
||||
},
|
||||
{
|
||||
path: 'goods/in',
|
||||
loadChildren: () =>
|
||||
import('@page/goods-in').then((m) => m.GoodsInModule),
|
||||
canActivate: [CanActivateGoodsInGuard],
|
||||
},
|
||||
{
|
||||
path: 'remission',
|
||||
loadChildren: () =>
|
||||
import('@page/remission').then((m) => m.PageRemissionModule),
|
||||
canActivate: [CanActivateRemissionGuard],
|
||||
},
|
||||
{
|
||||
path: 'package-inspection',
|
||||
loadChildren: () =>
|
||||
import('@page/package-inspection').then(
|
||||
(m) => m.PackageInspectionModule,
|
||||
),
|
||||
canActivate: [CanActivatePackageInspectionGuard],
|
||||
},
|
||||
{
|
||||
path: 'assortment',
|
||||
loadChildren: () =>
|
||||
import('@page/assortment').then((m) => m.AssortmentModule),
|
||||
canActivate: [CanActivateAssortmentGuard],
|
||||
},
|
||||
{ path: '**', redirectTo: 'task-calendar', pathMatch: 'full' },
|
||||
],
|
||||
resolve: { section: BranchSectionResolver },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: ':tabId',
|
||||
component: MainComponent,
|
||||
resolve: { process: tabResolverFn, tab: tabResolverFn },
|
||||
canActivate: [IsAuthenticatedGuard],
|
||||
children: [
|
||||
{
|
||||
path: 'return',
|
||||
loadChildren: () =>
|
||||
import('@isa/oms/feature/return-search').then((m) => m.routes),
|
||||
},
|
||||
{
|
||||
path: 'remission',
|
||||
children: [
|
||||
{
|
||||
path: 'return-receipt',
|
||||
loadChildren: () =>
|
||||
import(
|
||||
'@isa/remission/feature/remission-return-receipt-list'
|
||||
).then((m) => m.routes),
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
loadChildren: () =>
|
||||
import('@isa/remission/feature/remission-list').then(
|
||||
(m) => m.routes,
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
if (isDevMode()) {
|
||||
routes.unshift({
|
||||
path: 'preview',
|
||||
component: PreviewComponent,
|
||||
});
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(routes, { bindToComponentInputs: true }),
|
||||
TokenLoginModule,
|
||||
],
|
||||
exports: [RouterModule],
|
||||
providers: [provideScrollPositionRestoration()],
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
import { isDevMode, NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import {
|
||||
CanActivateCartGuard,
|
||||
CanActivateCartWithProcessIdGuard,
|
||||
CanActivateCustomerGuard,
|
||||
CanActivateCustomerOrdersGuard,
|
||||
CanActivateCustomerOrdersWithProcessIdGuard,
|
||||
CanActivateCustomerWithProcessIdGuard,
|
||||
CanActivateGoodsInGuard,
|
||||
CanActivateProductGuard,
|
||||
CanActivateProductWithProcessIdGuard,
|
||||
CanActivateRemissionGuard,
|
||||
CanActivateTaskCalendarGuard,
|
||||
IsAuthenticatedGuard,
|
||||
} from './guards';
|
||||
import { CanActivateAssortmentGuard } from './guards/can-activate-assortment.guard';
|
||||
import { CanActivatePackageInspectionGuard } from './guards/can-activate-package-inspection.guard';
|
||||
import { MainComponent } from './main.component';
|
||||
import { PreviewComponent } from './preview';
|
||||
import { BranchSectionResolver, CustomerSectionResolver, ProcessIdResolver } from './resolvers';
|
||||
import { TokenLoginComponent, TokenLoginModule } from './token-login';
|
||||
import { ProcessIdGuard } from './guards/process-id.guard';
|
||||
import { ActivateProcessIdGuard, ActivateProcessIdWithConfigKeyGuard } from './guards/activate-process-id.guard';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'login',
|
||||
children: [
|
||||
{ path: ':token', component: TokenLoginComponent },
|
||||
{ path: '**', redirectTo: 'kunde', pathMatch: 'full' },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
canActivate: [IsAuthenticatedGuard],
|
||||
children: [
|
||||
{
|
||||
path: 'kunde',
|
||||
component: MainComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'dashboard',
|
||||
loadChildren: () => import('@page/dashboard').then((m) => m.DashboardModule),
|
||||
},
|
||||
{
|
||||
path: 'product',
|
||||
loadChildren: () => import('@page/catalog').then((m) => m.PageCatalogModule),
|
||||
canActivate: [CanActivateProductGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/product',
|
||||
loadChildren: () => import('@page/catalog').then((m) => m.PageCatalogModule),
|
||||
canActivate: [CanActivateProductWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'order',
|
||||
loadChildren: () => import('@page/customer-order').then((m) => m.CustomerOrderModule),
|
||||
canActivate: [CanActivateCustomerOrdersGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/order',
|
||||
loadChildren: () => import('@page/customer-order').then((m) => m.CustomerOrderModule),
|
||||
canActivate: [CanActivateCustomerOrdersWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'customer',
|
||||
loadChildren: () => import('@page/customer').then((m) => m.CustomerModule),
|
||||
canActivate: [CanActivateCustomerGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/customer',
|
||||
loadChildren: () => import('@page/customer').then((m) => m.CustomerModule),
|
||||
canActivate: [CanActivateCustomerWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'cart',
|
||||
loadChildren: () => import('@page/checkout').then((m) => m.PageCheckoutModule),
|
||||
canActivate: [CanActivateCartGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/cart',
|
||||
loadChildren: () => import('@page/checkout').then((m) => m.PageCheckoutModule),
|
||||
canActivate: [CanActivateCartWithProcessIdGuard],
|
||||
},
|
||||
{
|
||||
path: 'pickup-shelf',
|
||||
canActivate: [ProcessIdGuard],
|
||||
// NOTE: This is a workaround for the canActivate guard not being called
|
||||
loadChildren: () => import('@page/pickup-shelf').then((m) => m.PickupShelfOutModule),
|
||||
},
|
||||
{
|
||||
path: ':processId/pickup-shelf',
|
||||
canActivate: [ActivateProcessIdGuard],
|
||||
loadChildren: () => import('@page/pickup-shelf').then((m) => m.PickupShelfOutModule),
|
||||
},
|
||||
{
|
||||
path: 'retoure',
|
||||
loadChildren: () => import('@page/retoure').then((m) => m.RetourePageModule),
|
||||
},
|
||||
{ path: '**', redirectTo: 'dashboard', pathMatch: 'full' },
|
||||
],
|
||||
resolve: { section: CustomerSectionResolver },
|
||||
},
|
||||
{
|
||||
path: 'filiale',
|
||||
component: MainComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'task-calendar',
|
||||
loadChildren: () => import('@page/task-calendar').then((m) => m.PageTaskCalendarModule),
|
||||
canActivate: [CanActivateTaskCalendarGuard],
|
||||
},
|
||||
{
|
||||
path: 'pickup-shelf',
|
||||
canActivate: [ActivateProcessIdWithConfigKeyGuard('pickupShelf')],
|
||||
// NOTE: This is a workaround for the canActivate guard not being called
|
||||
loadChildren: () => import('@page/pickup-shelf').then((m) => m.PickupShelfInModule),
|
||||
},
|
||||
{
|
||||
path: 'goods/in',
|
||||
loadChildren: () => import('@page/goods-in').then((m) => m.GoodsInModule),
|
||||
canActivate: [CanActivateGoodsInGuard],
|
||||
},
|
||||
{
|
||||
path: 'remission',
|
||||
loadChildren: () => import('@page/remission').then((m) => m.PageRemissionModule),
|
||||
canActivate: [CanActivateRemissionGuard],
|
||||
},
|
||||
{
|
||||
path: 'package-inspection',
|
||||
loadChildren: () => import('@page/package-inspection').then((m) => m.PackageInspectionModule),
|
||||
canActivate: [CanActivatePackageInspectionGuard],
|
||||
},
|
||||
{
|
||||
path: 'assortment',
|
||||
loadChildren: () => import('@page/assortment').then((m) => m.AssortmentModule),
|
||||
canActivate: [CanActivateAssortmentGuard],
|
||||
},
|
||||
{ path: '**', redirectTo: 'task-calendar', pathMatch: 'full' },
|
||||
],
|
||||
resolve: { section: BranchSectionResolver },
|
||||
},
|
||||
{ path: '**', redirectTo: 'kunde', pathMatch: 'full' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
if (isDevMode()) {
|
||||
routes.unshift({
|
||||
path: 'preview',
|
||||
component: PreviewComponent,
|
||||
});
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(routes, {
|
||||
paramsInheritanceStrategy: 'always',
|
||||
}),
|
||||
TokenLoginModule,
|
||||
],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
import { ActionReducer, MetaReducer, StoreModule } from '@ngrx/store';
|
||||
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||
import { storeFreeze } from 'ngrx-store-freeze';
|
||||
import packageInfo from 'packageJson';
|
||||
import { environment } from '../environments/environment';
|
||||
import { RootStateService } from './store/root-state.service';
|
||||
@@ -21,9 +22,7 @@ export function storeInLocalStorage(reducer: ActionReducer<any>): ActionReducer<
|
||||
};
|
||||
}
|
||||
|
||||
export const metaReducers: MetaReducer<RootState>[] = !environment.production
|
||||
? [storeInLocalStorage]
|
||||
: [storeInLocalStorage];
|
||||
export const metaReducers: MetaReducer<RootState>[] = !environment.production ? [storeFreeze, storeInLocalStorage] : [storeInLocalStorage];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import { HttpInterceptorFn, provideHttpClient, withInterceptors } from '@angular/common/http';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Config } from '@core/config';
|
||||
import { AvConfiguration } from '@generated/swagger/availability-api';
|
||||
import { CatConfiguration } from '@generated/swagger/cat-search-api';
|
||||
import { CheckoutConfiguration } from '@generated/swagger/checkout-api';
|
||||
import { CrmConfiguration } from '@generated/swagger/crm-api';
|
||||
import { EisConfiguration } from '@generated/swagger/eis-api';
|
||||
import { IsaConfiguration } from '@generated/swagger/isa-api';
|
||||
import { OmsConfiguration } from '@generated/swagger/oms-api';
|
||||
import { PrintConfiguration } from '@generated/swagger/print-api';
|
||||
import { RemiConfiguration } from '@generated/swagger/inventory-api';
|
||||
import { WwsConfiguration } from '@generated/swagger/wws-api';
|
||||
import { AvConfiguration } from '@swagger/availability';
|
||||
import { CatConfiguration } from '@swagger/cat';
|
||||
import { CheckoutConfiguration } from '@swagger/checkout';
|
||||
import { CrmConfiguration } from '@swagger/crm';
|
||||
import { EisConfiguration } from '@swagger/eis';
|
||||
import { IsaConfiguration } from '@swagger/isa';
|
||||
import { OmsConfiguration } from '@swagger/oms';
|
||||
import { PrintConfiguration } from '@swagger/print';
|
||||
import { RemiConfiguration } from '@swagger/remi';
|
||||
import { WwsConfiguration } from '@swagger/wws';
|
||||
|
||||
export function createConfigurationFactory(name: string) {
|
||||
return function (config: Config): { rootUrl: string } {
|
||||
@@ -18,13 +17,8 @@ export function createConfigurationFactory(name: string) {
|
||||
};
|
||||
}
|
||||
|
||||
const serviceWorkerInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
return next(req.clone({ setHeaders: { 'ngsw-bypass': 'true' } }));
|
||||
};
|
||||
|
||||
@NgModule({
|
||||
providers: [
|
||||
provideHttpClient(withInterceptors([serviceWorkerInterceptor])),
|
||||
{ provide: AvConfiguration, useFactory: createConfigurationFactory('av'), deps: [Config] },
|
||||
{ provide: CatConfiguration, useFactory: createConfigurationFactory('cat'), deps: [Config] },
|
||||
{ provide: CheckoutConfiguration, useFactory: createConfigurationFactory('checkout'), deps: [Config] },
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Renderer2 } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SwUpdate } from '@angular/service-worker';
|
||||
import { NotificationsHub } from '@hub/notifications';
|
||||
import { UserStateService } from '@generated/swagger/isa-api';
|
||||
import { UserStateService } from '@swagger/isa';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { AuthService } from '@core/auth';
|
||||
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
|
||||
import {
|
||||
Component,
|
||||
effect,
|
||||
HostListener,
|
||||
inject,
|
||||
Inject,
|
||||
Injector,
|
||||
OnInit,
|
||||
Renderer2,
|
||||
signal,
|
||||
untracked,
|
||||
DOCUMENT
|
||||
} from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Component, effect, HostListener, Inject, OnInit, Renderer2, signal, untracked } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { SwUpdate } from '@angular/service-worker';
|
||||
import { ApplicationService } from '@core/application';
|
||||
@@ -19,10 +7,10 @@ import { Config } from '@core/config';
|
||||
import { NotificationsHub } from '@hub/notifications';
|
||||
import packageInfo from 'packageJson';
|
||||
import { asapScheduler, interval, Subscription } from 'rxjs';
|
||||
import { UserStateService } from '@generated/swagger/isa-api';
|
||||
import { UserStateService } from '@swagger/isa';
|
||||
import { IsaLogProvider } from './providers';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { AuthService, LoginStrategy } from '@core/auth';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
import { injectOnline$ } from './services/network-status.service';
|
||||
import { toSignal } from '@angular/core/rxjs-interop';
|
||||
@@ -45,11 +33,8 @@ import { animate, style, transition, trigger } from '@angular/animations';
|
||||
]),
|
||||
]),
|
||||
],
|
||||
standalone: false,
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
readonly injector = inject(Injector);
|
||||
|
||||
$online = toSignal(injectOnline$());
|
||||
|
||||
$offlineBannerVisible = signal(false);
|
||||
@@ -133,10 +118,7 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
|
||||
logVersion() {
|
||||
console.log(
|
||||
`%c${this._config.get('title')}\r\nVersion: ${packageInfo.version}`,
|
||||
'font-weight: bold; font-size: 20px;',
|
||||
);
|
||||
console.log(`%c${this._config.get('title')}\r\nVersion: ${packageInfo.version}`, 'font-weight: bold; font-size: 20px;');
|
||||
}
|
||||
|
||||
determinePlatform() {
|
||||
@@ -198,9 +180,15 @@ export class AppComponent implements OnInit {
|
||||
if (this._document.hidden && this._authService.isAuthenticated()) {
|
||||
this._authService.refresh();
|
||||
} else if (!this._authService.isAuthenticated()) {
|
||||
const strategy = this.injector.get(LoginStrategy);
|
||||
|
||||
return strategy.login('Sie sind nicht mehr angemeldet');
|
||||
return this._modal
|
||||
.open({
|
||||
content: UiMessageModalComponent,
|
||||
title: 'Sie sind nicht mehr angemeldet',
|
||||
data: { message: 'Sie werden neu angemeldet' },
|
||||
})
|
||||
.afterClosed$.subscribe(() => {
|
||||
this._authService.login();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,11 @@
|
||||
import {
|
||||
HTTP_INTERCEPTORS,
|
||||
provideHttpClient,
|
||||
withInterceptorsFromDi,
|
||||
} from '@angular/common/http';
|
||||
import {
|
||||
DEFAULT_CURRENCY_CODE,
|
||||
ErrorHandler,
|
||||
Injector,
|
||||
LOCALE_ID,
|
||||
NgModule,
|
||||
inject,
|
||||
provideAppInitializer,
|
||||
} from '@angular/core';
|
||||
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { APP_INITIALIZER, ErrorHandler, Injector, LOCALE_ID, NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { PlatformModule } from '@angular/cdk/platform';
|
||||
|
||||
import { Config } from '@core/config';
|
||||
import { AuthModule, AuthService, LoginStrategy } from '@core/auth';
|
||||
import { Config, ConfigModule, JsonConfigLoader } from '@core/config';
|
||||
import { AuthModule, AuthService } from '@core/auth';
|
||||
import { CoreCommandModule } from '@core/command';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
@@ -29,10 +17,7 @@ import { environment } from '../environments/environment';
|
||||
import { AppSwaggerModule } from './app-swagger.module';
|
||||
import { AppDomainModule } from './app-domain.module';
|
||||
import { UiModalModule } from '@ui/modal';
|
||||
import {
|
||||
NotificationsHubModule,
|
||||
NOTIFICATIONS_HUB_OPTIONS,
|
||||
} from '@hub/notifications';
|
||||
import { NotificationsHubModule, NOTIFICATIONS_HUB_OPTIONS } from '@hub/notifications';
|
||||
import { SignalRHubOptions } from '@core/signalr';
|
||||
import { CoreBreadcrumbModule } from '@core/breadcrumb';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
@@ -44,11 +29,7 @@ import { HttpErrorInterceptor } from './interceptors';
|
||||
import { CoreLoggerModule, LOG_PROVIDER } from '@core/logger';
|
||||
import { IsaLogProvider } from './providers';
|
||||
import { IsaErrorHandler } from './providers/isa.error-handler';
|
||||
import {
|
||||
ScanAdapterModule,
|
||||
ScanAdapterService,
|
||||
ScanditScanAdapterModule,
|
||||
} from '@adapter/scan';
|
||||
import { ScanAdapterModule, ScanAdapterService, ScanditScanAdapterModule } from '@adapter/scan';
|
||||
import { RootStateService } from './store/root-state.service';
|
||||
import * as Commands from './commands';
|
||||
import { PreviewComponent } from './preview';
|
||||
@@ -57,34 +38,28 @@ import { ShellModule } from '@shared/shell';
|
||||
import { MainComponent } from './main.component';
|
||||
import { IconModule } from '@shared/components/icon';
|
||||
import { NgIconsModule } from '@ng-icons/core';
|
||||
import {
|
||||
matClose,
|
||||
matWifi,
|
||||
matWifiOff,
|
||||
} from '@ng-icons/material-icons/baseline';
|
||||
import { matClose, matWifi, matWifiOff } from '@ng-icons/material-icons/baseline';
|
||||
import { NetworkStatusService } from './services/network-status.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { provideMatomo } from 'ngx-matomo-client';
|
||||
import { withRouter, withRouteData } from 'ngx-matomo-client';
|
||||
import {
|
||||
provideLogging,
|
||||
withLogLevel,
|
||||
LogLevel,
|
||||
withSink,
|
||||
ConsoleLogSink,
|
||||
} from '@isa/core/logging';
|
||||
|
||||
registerLocaleData(localeDe, localeDeExtra);
|
||||
registerLocaleData(localeDe, 'de', localeDeExtra);
|
||||
|
||||
export function _appInitializerFactory(config: Config, injector: Injector) {
|
||||
export function _appInitializerFactory(
|
||||
config: Config,
|
||||
auth: AuthService,
|
||||
injector: Injector,
|
||||
scanAdapter: ScanAdapterService,
|
||||
nativeContainer: NativeContainerService,
|
||||
networkStatus: NetworkStatusService,
|
||||
) {
|
||||
return async () => {
|
||||
const statusElement = document.querySelector('#init-status');
|
||||
const laoderElement = document.querySelector('#init-loader');
|
||||
|
||||
try {
|
||||
let online = false;
|
||||
const networkStatus = injector.get(NetworkStatusService);
|
||||
|
||||
while (!online) {
|
||||
online = await firstValueFrom(networkStatus.online$);
|
||||
|
||||
@@ -96,43 +71,28 @@ export function _appInitializerFactory(config: Config, injector: Injector) {
|
||||
}
|
||||
|
||||
statusElement.innerHTML = 'Konfigurationen werden geladen...';
|
||||
|
||||
statusElement.innerHTML = 'Scanner wird initialisiert...';
|
||||
const scanAdapter = injector.get(ScanAdapterService);
|
||||
await scanAdapter.init();
|
||||
|
||||
await config.init();
|
||||
statusElement.innerHTML = 'Authentifizierung wird geprüft...';
|
||||
await auth.init();
|
||||
|
||||
const auth = injector.get(AuthService);
|
||||
try {
|
||||
await auth.init();
|
||||
} catch (error) {
|
||||
statusElement.innerHTML = 'Authentifizierung wird durchgeführt...';
|
||||
const strategy = injector.get(LoginStrategy);
|
||||
await strategy.login();
|
||||
if (auth.isAuthenticated()) {
|
||||
statusElement.innerHTML = 'App wird initialisiert...';
|
||||
const state = injector.get(RootStateService);
|
||||
await state.init();
|
||||
}
|
||||
|
||||
statusElement.innerHTML = 'App wird initialisiert...';
|
||||
const state = injector.get(RootStateService);
|
||||
await state.init();
|
||||
|
||||
statusElement.innerHTML = 'Native Container wird initialisiert...';
|
||||
const nativeContainer = injector.get(NativeContainerService);
|
||||
await nativeContainer.init();
|
||||
|
||||
statusElement.innerHTML = 'Scanner wird initialisiert...';
|
||||
await scanAdapter.init();
|
||||
} catch (error) {
|
||||
laoderElement.remove();
|
||||
statusElement.classList.add('text-xl');
|
||||
statusElement.innerHTML +=
|
||||
'⚡<br><br><b>Fehler bei der Initialisierung</b><br><br>Bitte prüfen Sie die Netzwerkverbindung (WLAN).<br><br>';
|
||||
statusElement.innerHTML = '<b>Fehler bei der Initialisierung</b><br><br>Bitte prüfen Sie die Netzwerkverbindung (WLAN).<br><br>';
|
||||
|
||||
const reload = document.createElement('button');
|
||||
reload.classList.add(
|
||||
'bg-brand',
|
||||
'text-white',
|
||||
'p-2',
|
||||
'rounded',
|
||||
'cursor-pointer',
|
||||
);
|
||||
reload.classList.add('bg-brand', 'text-white', 'p-2', 'rounded', 'cursor-pointer');
|
||||
reload.innerHTML = 'App neu laden';
|
||||
reload.onclick = () => window.location.reload();
|
||||
statusElement.appendChild(reload);
|
||||
@@ -155,10 +115,7 @@ export function _appInitializerFactory(config: Config, injector: Injector) {
|
||||
};
|
||||
}
|
||||
|
||||
export function _notificationsHubOptionsFactory(
|
||||
config: Config,
|
||||
auth: AuthService,
|
||||
): SignalRHubOptions {
|
||||
export function _notificationsHubOptionsFactory(config: Config, auth: AuthService): SignalRHubOptions {
|
||||
const options = { ...config.get('hubs').notifications };
|
||||
options.httpOptions.accessTokenFactory = () => auth.getToken();
|
||||
return options;
|
||||
@@ -166,15 +123,19 @@ export function _notificationsHubOptionsFactory(
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent, MainComponent],
|
||||
bootstrap: [AppComponent],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
HttpClientModule,
|
||||
ShellModule.forRoot(),
|
||||
AppRoutingModule,
|
||||
AppSwaggerModule,
|
||||
AppDomainModule,
|
||||
CoreBreadcrumbModule.forRoot(),
|
||||
ConfigModule.forRoot({
|
||||
useConfigLoader: JsonConfigLoader,
|
||||
jsonConfigLoaderUrl: '/config/config.json',
|
||||
}),
|
||||
CoreCommandModule.forRoot(Object.values(Commands)),
|
||||
CoreLoggerModule.forRoot(),
|
||||
AppStoreModule,
|
||||
@@ -195,13 +156,12 @@ export function _notificationsHubOptionsFactory(
|
||||
NgIconsModule.withIcons({ matWifiOff, matClose, matWifi }),
|
||||
],
|
||||
providers: [
|
||||
provideAppInitializer(() => {
|
||||
const initializerFn = _appInitializerFactory(
|
||||
inject(Config),
|
||||
inject(Injector),
|
||||
);
|
||||
return initializerFn();
|
||||
}),
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: _appInitializerFactory,
|
||||
multi: true,
|
||||
deps: [Config, AuthService, Injector, ScanAdapterService, NativeContainerService, NetworkStatusService],
|
||||
},
|
||||
{
|
||||
provide: NOTIFICATIONS_HUB_OPTIONS,
|
||||
useFactory: _notificationsHubOptionsFactory,
|
||||
@@ -222,17 +182,7 @@ export function _notificationsHubOptionsFactory(
|
||||
useClass: IsaErrorHandler,
|
||||
},
|
||||
{ provide: LOCALE_ID, useValue: 'de-DE' },
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
provideMatomo(
|
||||
{ trackerUrl: 'https://matomo.paragon-data.net', siteId: '1' },
|
||||
withRouter(),
|
||||
withRouteData(),
|
||||
),
|
||||
provideLogging(withLogLevel(LogLevel.Debug), withSink(ConsoleLogSink)),
|
||||
{
|
||||
provide: DEFAULT_CURRENCY_CODE,
|
||||
useValue: 'EUR',
|
||||
},
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
@@ -3,14 +3,11 @@ import { Router } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { ActionHandler } from '@core/command';
|
||||
import { Result } from '@domain/defs';
|
||||
import { CustomerInfoDTO } from '@generated/swagger/crm-api';
|
||||
import { CustomerInfoDTO } from '@swagger/crm';
|
||||
|
||||
@Injectable()
|
||||
export class CreateCustomerCommand extends ActionHandler<Result<CustomerInfoDTO[]>> {
|
||||
constructor(
|
||||
private _router: Router,
|
||||
private _application: ApplicationService,
|
||||
) {
|
||||
constructor(private _router: Router, private _application: ApplicationService) {
|
||||
super('CREATE_CUSTOMER');
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ApplicationService } from '@core/application';
|
||||
import { ActionHandler } from '@core/command';
|
||||
import { Result } from '@domain/defs';
|
||||
import { encodeFormData, mapCustomerInfoDtoToCustomerCreateFormData } from '@page/customer';
|
||||
import { CustomerInfoDTO } from '@generated/swagger/crm-api';
|
||||
import { CustomerInfoDTO } from '@swagger/crm';
|
||||
|
||||
@Injectable()
|
||||
export class CreateKubiCustomerCommand extends ActionHandler<Result<CustomerInfoDTO[]>> {
|
||||
@@ -40,12 +40,9 @@ export class CreateKubiCustomerCommand extends ActionHandler<Result<CustomerInfo
|
||||
customerType = 'store';
|
||||
}
|
||||
|
||||
await this._router.navigate(
|
||||
['/kunde', this._application.activatedProcessId, 'customer', 'create', `${customerType}-p4m`],
|
||||
{
|
||||
queryParams: { formData },
|
||||
},
|
||||
);
|
||||
await this._router.navigate(['/kunde', this._application.activatedProcessId, 'customer', 'create', `${customerType}-p4m`], {
|
||||
queryParams: { formData },
|
||||
});
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,12 @@ import { ActionHandler } from '@core/command';
|
||||
import { Result } from '@domain/defs';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
import { CustomerInfoDTO } from '@generated/swagger/crm-api';
|
||||
import { CustomerInfoDTO } from '@swagger/crm';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
|
||||
@Injectable()
|
||||
export class PrintKubiCustomerCommand extends ActionHandler<Result<CustomerInfoDTO[]>> {
|
||||
constructor(
|
||||
private _uiModal: UiModalService,
|
||||
private _printerService: DomainPrinterService,
|
||||
) {
|
||||
constructor(private _uiModal: UiModalService, private _printerService: DomainPrinterService) {
|
||||
super('PRINT_KUBI_AGB');
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,7 @@ import { ApplicationService } from '@core/application';
|
||||
import { Config } from '@core/config';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
export const ActivateProcessIdGuard: CanActivateFn = async (
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot,
|
||||
) => {
|
||||
export const ActivateProcessIdGuard: CanActivateFn = async (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
|
||||
const application = inject(ApplicationService);
|
||||
|
||||
const processIdStr = route.params.processId;
|
||||
@@ -30,18 +27,20 @@ export const ActivateProcessIdGuard: CanActivateFn = async (
|
||||
return true;
|
||||
};
|
||||
|
||||
export const ActivateProcessIdWithConfigKeyGuard: (key: string) => CanActivateFn =
|
||||
(key) => async (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
|
||||
const application = inject(ApplicationService);
|
||||
const config = inject(Config);
|
||||
export const ActivateProcessIdWithConfigKeyGuard: (key: string) => CanActivateFn = (key) => async (
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot
|
||||
) => {
|
||||
const application = inject(ApplicationService);
|
||||
const config = inject(Config);
|
||||
|
||||
const processId = config.get(`process.ids.${key}`);
|
||||
const processId = config.get(`process.ids.${key}`);
|
||||
|
||||
if (isNaN(processId)) {
|
||||
return false;
|
||||
}
|
||||
if (isNaN(processId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
application.activateProcess(processId);
|
||||
application.activateProcess(processId);
|
||||
|
||||
return true;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -6,16 +6,10 @@ import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateAssortmentGuard {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _config: Config,
|
||||
) {}
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _config: Config) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService
|
||||
.getProcessById$(this._config.get('process.ids.assortment'))
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const process = await this._applicationService.getProcessById$(this._config.get('process.ids.assortment')).pipe(first()).toPromise();
|
||||
if (!process) {
|
||||
await this._applicationService.createProcess({
|
||||
id: this._config.get('process.ids.assortment'),
|
||||
|
||||
@@ -8,7 +8,10 @@ export class CanActivateCartWithProcessIdGuard {
|
||||
constructor(private readonly _applicationService: ApplicationService) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService.getProcessById$(+route.params.processId).pipe(first()).toPromise();
|
||||
const process = await this._applicationService
|
||||
.getProcessById$(+route.params.processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
// if (!(process?.type === 'cart')) {
|
||||
// // TODO:
|
||||
|
||||
@@ -14,10 +14,7 @@ export class CanActivateCartGuard {
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
|
||||
let lastActivatedProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$('customer', 'cart')
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
if (!lastActivatedProcessId) {
|
||||
lastActivatedProcessId = Date.now();
|
||||
|
||||
@@ -6,13 +6,13 @@ import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateCustomerOrdersWithProcessIdGuard {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _breadcrumbService: BreadcrumbService,
|
||||
) {}
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _breadcrumbService: BreadcrumbService) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService.getProcessById$(+route.params.processId).pipe(first()).toPromise();
|
||||
const process = await this._applicationService
|
||||
.getProcessById$(+route.params.processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
if (!process) {
|
||||
const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
|
||||
@@ -31,7 +31,10 @@ export class CanActivateCustomerOrdersWithProcessIdGuard {
|
||||
|
||||
// Fix #3292: Alle Breadcrumbs die nichts mit dem aktuellen Prozess zu tun haben, müssen removed werden
|
||||
async removeBreadcrumbWithSameProcessId(route: ActivatedRouteSnapshot) {
|
||||
const crumbs = await this._breadcrumbService.getBreadcrumbByKey$(+route.params.processId).pipe(first()).toPromise();
|
||||
const crumbs = await this._breadcrumbService
|
||||
.getBreadcrumbByKey$(+route.params.processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
// Entferne alle Crumbs die nichts mit den Kundenbestellungen zu tun haben
|
||||
if (crumbs.length > 1) {
|
||||
|
||||
@@ -17,17 +17,11 @@ export class CanActivateCustomerOrdersGuard {
|
||||
const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
|
||||
|
||||
let lastActivatedProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$('customer', 'cart')
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
const lastActivatedCartCheckoutProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout')
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
const activatedProcessId = await this._applicationService.getActivatedProcessId$().pipe(first()).toPromise();
|
||||
|
||||
@@ -6,13 +6,13 @@ import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateCustomerWithProcessIdGuard {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _breadcrumbService: BreadcrumbService,
|
||||
) {}
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _breadcrumbService: BreadcrumbService) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService.getProcessById$(+route.params.processId).pipe(first()).toPromise();
|
||||
const process = await this._applicationService
|
||||
.getProcessById$(+route.params.processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
// if (!(process?.type === 'cart')) {
|
||||
// // TODO:
|
||||
@@ -37,7 +37,10 @@ export class CanActivateCustomerWithProcessIdGuard {
|
||||
|
||||
// Fix #3292: Alle Breadcrumbs die nichts mit dem aktuellen Prozess zu tun haben, müssen removed werden
|
||||
async removeBreadcrumbWithSameProcessId(route: ActivatedRouteSnapshot) {
|
||||
const crumbs = await this._breadcrumbService.getBreadcrumbByKey$(+route.params.processId).pipe(first()).toPromise();
|
||||
const crumbs = await this._breadcrumbService
|
||||
.getBreadcrumbByKey$(+route.params.processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
// Entferne alle Crumbs die nichts mit der Kundensuche zu tun haben
|
||||
if (crumbs.length > 1) {
|
||||
|
||||
@@ -1,22 +1,12 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
} from "@angular/router";
|
||||
import { ApplicationProcess, ApplicationService } from "@core/application";
|
||||
import { DomainCheckoutService } from "@domain/checkout";
|
||||
import { logger } from "@isa/core/logging";
|
||||
import { CustomerSearchNavigation } from "@shared/services/navigation";
|
||||
import { first } from "rxjs/operators";
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationProcess, ApplicationService } from '@core/application';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { CustomerSearchNavigation } from '@shared/services/navigation';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: "root" })
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateCustomerGuard {
|
||||
#logger = logger(() => ({
|
||||
context: "CanActivateCustomerGuard",
|
||||
tags: ["guard", "customer", "navigation"],
|
||||
}));
|
||||
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _checkoutService: DomainCheckoutService,
|
||||
@@ -24,77 +14,27 @@ export class CanActivateCustomerGuard {
|
||||
private readonly _navigation: CustomerSearchNavigation,
|
||||
) {}
|
||||
|
||||
async canActivate(
|
||||
route: ActivatedRouteSnapshot,
|
||||
{ url }: RouterStateSnapshot,
|
||||
) {
|
||||
if (url.startsWith("/kunde/customer/search/")) {
|
||||
const processId = Date.now(); // Generate a new process ID
|
||||
// Extract parts before and after the pattern
|
||||
const parts = url.split("/kunde/customer/");
|
||||
if (parts.length === 2) {
|
||||
const prefix = parts[0] + "/kunde/";
|
||||
const suffix = "customer/" + parts[1];
|
||||
|
||||
// Construct the new URL with process ID inserted
|
||||
const newUrl = `${prefix}${processId}/${suffix}`;
|
||||
|
||||
this.#logger.info("Redirecting to URL with process ID", () => ({
|
||||
originalUrl: url,
|
||||
newUrl,
|
||||
processId,
|
||||
}));
|
||||
|
||||
// Navigate to the new URL and prevent original navigation
|
||||
this._router.navigateByUrl(newUrl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const processes = await this._applicationService
|
||||
.getProcesses$("customer")
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const lastActivatedProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$("customer", "cart")
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
|
||||
let lastActivatedProcessId = (
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
const lastActivatedCartCheckoutProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$("customer", "cart-checkout")
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
const lastActivatedGoodsOutProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$("customer", "goods-out")
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'goods-out').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
const activatedProcessId = await this._applicationService
|
||||
.getActivatedProcessId$()
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const activatedProcessId = await this._applicationService.getActivatedProcessId$().pipe(first()).toPromise();
|
||||
|
||||
// Darf nur reinkommen wenn der aktuell aktive Tab ein Bestellabschluss Tab ist
|
||||
if (
|
||||
!!lastActivatedCartCheckoutProcessId &&
|
||||
lastActivatedCartCheckoutProcessId === activatedProcessId
|
||||
) {
|
||||
await this.fromCartCheckoutProcess(
|
||||
processes,
|
||||
lastActivatedCartCheckoutProcessId,
|
||||
);
|
||||
if (!!lastActivatedCartCheckoutProcessId && lastActivatedCartCheckoutProcessId === activatedProcessId) {
|
||||
await this.fromCartCheckoutProcess(processes, lastActivatedCartCheckoutProcessId);
|
||||
return false;
|
||||
} else if (
|
||||
!!lastActivatedGoodsOutProcessId &&
|
||||
lastActivatedGoodsOutProcessId === activatedProcessId
|
||||
) {
|
||||
} else if (!!lastActivatedGoodsOutProcessId && lastActivatedGoodsOutProcessId === activatedProcessId) {
|
||||
await this.fromGoodsOutProcess(processes, lastActivatedGoodsOutProcessId);
|
||||
return false;
|
||||
}
|
||||
@@ -119,28 +59,25 @@ export class CanActivateCustomerGuard {
|
||||
const newProcessId = Date.now();
|
||||
await this._applicationService.createProcess({
|
||||
id: newProcessId,
|
||||
type: "cart",
|
||||
section: "customer",
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === "cart"))}`,
|
||||
type: 'cart',
|
||||
section: 'customer',
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
|
||||
});
|
||||
|
||||
await this.navigateToDefaultRoute(newProcessId);
|
||||
}
|
||||
|
||||
// Bei offener Bestellbestätigung und Klick auf Footer Kundensuche
|
||||
async fromCartCheckoutProcess(
|
||||
processes: ApplicationProcess[],
|
||||
processId: number,
|
||||
) {
|
||||
async fromCartCheckoutProcess(processes: ApplicationProcess[], processId: number) {
|
||||
// Um alle Checkout Daten zu resetten die mit dem Prozess assoziiert sind
|
||||
this._checkoutService.removeProcess({ processId });
|
||||
|
||||
// Ändere type cart-checkout zu cart
|
||||
this._applicationService.patchProcess(processId, {
|
||||
id: processId,
|
||||
type: "cart",
|
||||
section: "customer",
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === "cart"))}`,
|
||||
type: 'cart',
|
||||
section: 'customer',
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
|
||||
data: {},
|
||||
});
|
||||
|
||||
@@ -149,31 +86,22 @@ export class CanActivateCustomerGuard {
|
||||
}
|
||||
|
||||
// Bei offener Warenausgabe und Klick auf Footer Kundensuche
|
||||
async fromGoodsOutProcess(
|
||||
processes: ApplicationProcess[],
|
||||
processId: number,
|
||||
) {
|
||||
const buyer = await this._checkoutService
|
||||
.getBuyer({ processId })
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const customerFeatures = await this._checkoutService
|
||||
.getCustomerFeatures({ processId })
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
async fromGoodsOutProcess(processes: ApplicationProcess[], processId: number) {
|
||||
const buyer = await this._checkoutService.getBuyer({ processId }).pipe(first()).toPromise();
|
||||
const customerFeatures = await this._checkoutService.getCustomerFeatures({ processId }).pipe(first()).toPromise();
|
||||
const name = buyer
|
||||
? customerFeatures?.b2b
|
||||
? buyer.organisation?.name
|
||||
? buyer.organisation?.name
|
||||
: buyer.lastName
|
||||
: buyer.lastName
|
||||
: `Vorgang ${this.processNumber(processes.filter((process) => process.type === "cart"))}`;
|
||||
: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`;
|
||||
|
||||
// Ändere type goods-out zu cart
|
||||
this._applicationService.patchProcess(processId, {
|
||||
id: processId,
|
||||
type: "cart",
|
||||
section: "customer",
|
||||
type: 'cart',
|
||||
section: 'customer',
|
||||
name,
|
||||
});
|
||||
|
||||
@@ -182,20 +110,12 @@ export class CanActivateCustomerGuard {
|
||||
}
|
||||
|
||||
processNumber(processes: ApplicationProcess[]) {
|
||||
const processNumbers = processes?.map((process) =>
|
||||
Number(process?.name?.replace(/\D/g, "")),
|
||||
);
|
||||
return !!processNumbers && processNumbers.length > 0
|
||||
? this.findMissingNumber(processNumbers)
|
||||
: 1;
|
||||
const processNumbers = processes?.map((process) => Number(process?.name?.replace(/\D/g, '')));
|
||||
return !!processNumbers && processNumbers.length > 0 ? this.findMissingNumber(processNumbers) : 1;
|
||||
}
|
||||
|
||||
findMissingNumber(processNumbers: number[]) {
|
||||
for (
|
||||
let missingNumber = 1;
|
||||
missingNumber < Math.max(...processNumbers);
|
||||
missingNumber++
|
||||
) {
|
||||
for (let missingNumber = 1; missingNumber < Math.max(...processNumbers); missingNumber++) {
|
||||
if (!processNumbers.find((number) => number === missingNumber)) {
|
||||
return missingNumber;
|
||||
}
|
||||
|
||||
@@ -3,21 +3,13 @@ import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { Config } from '@core/config';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { z } from 'zod';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateGoodsInGuard {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _config: Config,
|
||||
) {}
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _config: Config) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const pid = this._config.get('process.ids.goodsIn', z.number());
|
||||
const process = await this._applicationService
|
||||
.getProcessById$(pid)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const process = await this._applicationService.getProcessById$(this._config.get('process.ids.goodsIn')).pipe(first()).toPromise();
|
||||
if (!process) {
|
||||
await this._applicationService.createProcess({
|
||||
id: this._config.get('process.ids.goodsIn'),
|
||||
@@ -26,9 +18,7 @@ export class CanActivateGoodsInGuard {
|
||||
name: '',
|
||||
});
|
||||
}
|
||||
this._applicationService.activateProcess(
|
||||
this._config.get('process.ids.goodsIn'),
|
||||
);
|
||||
this._applicationService.activateProcess(this._config.get('process.ids.goodsIn'));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateGoodsOutWithProcessIdGuard {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _breadcrumbService: BreadcrumbService,
|
||||
) {}
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _breadcrumbService: BreadcrumbService) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService.getProcessById$(+route.params.processId).pipe(first()).toPromise();
|
||||
const process = await this._applicationService
|
||||
.getProcessById$(+route.params.processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
if (!process) {
|
||||
// const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
|
||||
@@ -31,7 +31,10 @@ export class CanActivateGoodsOutWithProcessIdGuard {
|
||||
|
||||
// Fix #3292: Alle Breadcrumbs die nichts mit dem aktuellen Prozess zu tun haben, müssen removed werden
|
||||
async removeBreadcrumbWithSameProcessId(route: ActivatedRouteSnapshot) {
|
||||
const crumbs = await this._breadcrumbService.getBreadcrumbByKey$(+route.params.processId).pipe(first()).toPromise();
|
||||
const crumbs = await this._breadcrumbService
|
||||
.getBreadcrumbByKey$(+route.params.processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
// Entferne alle Crumbs die nichts mit der Warenausgabe zu tun haben
|
||||
if (crumbs.length > 1) {
|
||||
|
||||
@@ -9,7 +9,7 @@ export class CanActivateGoodsOutGuard {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _checkoutService: DomainCheckoutService,
|
||||
private readonly _router: Router,
|
||||
private readonly _router: Router
|
||||
) {}
|
||||
|
||||
// !!! Ticket #3272 Code soll vorerst bestehen bleiben. Prozess Warenausgabe soll wieder Vorgang heißen (wie aktuell im Produktiv), bis zum neuen Navigationskonzept
|
||||
@@ -103,17 +103,11 @@ export class CanActivateGoodsOutGuard {
|
||||
const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
|
||||
|
||||
let lastActivatedProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$('customer', 'cart')
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
const lastActivatedCartCheckoutProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout')
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
const activatedProcessId = await this._applicationService.getActivatedProcessId$().pipe(first()).toPromise();
|
||||
|
||||
@@ -6,10 +6,7 @@ import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivatePackageInspectionGuard {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _config: Config,
|
||||
) {}
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _config: Config) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService
|
||||
|
||||
@@ -6,13 +6,13 @@ import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateProductWithProcessIdGuard {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _breadcrumbService: BreadcrumbService,
|
||||
) {}
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _breadcrumbService: BreadcrumbService) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService.getProcessById$(+route.params.processId).pipe(first()).toPromise();
|
||||
const process = await this._applicationService
|
||||
.getProcessById$(+route.params.processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
// if (!(process?.type === 'cart')) {
|
||||
// // TODO:
|
||||
@@ -37,7 +37,10 @@ export class CanActivateProductWithProcessIdGuard {
|
||||
|
||||
// Fix #3292: Alle Breadcrumbs die nichts mit dem aktuellen Prozess zu tun haben, müssen removed werden
|
||||
async removeBreadcrumbWithSameProcessId(route: ActivatedRouteSnapshot) {
|
||||
const crumbs = await this._breadcrumbService.getBreadcrumbByKey$(+route.params.processId).pipe(first()).toPromise();
|
||||
const crumbs = await this._breadcrumbService
|
||||
.getBreadcrumbByKey$(+route.params.processId)
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
// Entferne alle Crumbs die nichts mit der Artikelsuche zu tun haben
|
||||
if (crumbs.length > 1) {
|
||||
|
||||
@@ -16,24 +16,15 @@ export class CanActivateProductGuard {
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
|
||||
let lastActivatedProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$('customer', 'cart')
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
const lastActivatedCartCheckoutProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout')
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
const lastActivatedGoodsOutProcessId = (
|
||||
await this._applicationService
|
||||
.getLastActivatedProcessWithSectionAndType$('customer', 'goods-out')
|
||||
.pipe(first())
|
||||
.toPromise()
|
||||
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'goods-out').pipe(first()).toPromise()
|
||||
)?.id;
|
||||
|
||||
const activatedProcessId = await this._applicationService.getActivatedProcessId$().pipe(first()).toPromise();
|
||||
|
||||
@@ -9,14 +9,11 @@ export class CanActivateRemissionGuard {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _config: Config,
|
||||
private readonly _router: Router,
|
||||
private readonly _router: Router
|
||||
) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService
|
||||
.getProcessById$(this._config.get('process.ids.remission'))
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const process = await this._applicationService.getProcessById$(this._config.get('process.ids.remission')).pipe(first()).toPromise();
|
||||
if (!process) {
|
||||
await this._applicationService.createProcess({
|
||||
id: this._config.get('process.ids.remission'),
|
||||
|
||||
@@ -6,16 +6,10 @@ import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateTaskCalendarGuard {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _config: Config,
|
||||
) {}
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _config: Config) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService
|
||||
.getProcessById$(this._config.get('process.ids.taskCalendar'))
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const process = await this._applicationService.getProcessById$(this._config.get('process.ids.taskCalendar')).pipe(first()).toPromise();
|
||||
if (!process) {
|
||||
await this._applicationService.createProcess({
|
||||
id: this._config.get('process.ids.taskCalendar'),
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { ScanAdapterService } from '@adapter/scan';
|
||||
import { AuthService as IsaAuthService } from '@generated/swagger/isa-api';
|
||||
import { AuthService as IsaAuthService } from '@swagger/isa';
|
||||
import { UiConfirmModalComponent, UiErrorModalComponent, UiModalResult, UiModalService } from '@ui/modal';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { injectNetworkStatus$ } from '../services/network-status.service';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { take } from 'rxjs/operators';
|
||||
|
||||
export const ProcessIdGuard: CanActivateFn = async (
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot,
|
||||
state: RouterStateSnapshot
|
||||
): Promise<boolean | UrlTree> => {
|
||||
const application = inject(ApplicationService);
|
||||
const router = inject(Router);
|
||||
|
||||
@@ -1,66 +1,66 @@
|
||||
// import { HttpErrorInterceptor } from './http-error.interceptor';
|
||||
// import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
|
||||
// import { UiMessageModalComponent, UiModalResult, UiModalService } from '@ui/modal';
|
||||
// import { of, Subject, throwError } from 'rxjs';
|
||||
// import { HttpErrorResponse } from '@angular/common/http';
|
||||
// import { AuthService } from '@core/auth';
|
||||
import { HttpErrorInterceptor } from './http-error.interceptor';
|
||||
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
|
||||
import { UiMessageModalComponent, UiModalResult, UiModalService } from '@ui/modal';
|
||||
import { of, Subject, throwError } from 'rxjs';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { AuthService } from '@core/auth';
|
||||
|
||||
// describe('HttpErrorInterceptor', () => {
|
||||
// let spectator: SpectatorService<HttpErrorInterceptor>;
|
||||
// let modalMock: jasmine.SpyObj<UiModalService>;
|
||||
// let httpErrorInterceptor: HttpErrorInterceptor;
|
||||
describe('HttpErrorInterceptor', () => {
|
||||
let spectator: SpectatorService<HttpErrorInterceptor>;
|
||||
let modalMock: jasmine.SpyObj<UiModalService>;
|
||||
let httpErrorInterceptor: HttpErrorInterceptor;
|
||||
|
||||
// const createService = createServiceFactory({
|
||||
// service: HttpErrorInterceptor,
|
||||
// mocks: [UiModalService, AuthService],
|
||||
// });
|
||||
const createService = createServiceFactory({
|
||||
service: HttpErrorInterceptor,
|
||||
mocks: [UiModalService, AuthService],
|
||||
});
|
||||
|
||||
// beforeEach(() => {
|
||||
// spectator = createService();
|
||||
// httpErrorInterceptor = spectator.service;
|
||||
// modalMock = spectator.inject(UiModalService);
|
||||
beforeEach(() => {
|
||||
spectator = createService();
|
||||
httpErrorInterceptor = spectator.service;
|
||||
modalMock = spectator.inject(UiModalService);
|
||||
|
||||
// modalMock.open.and.returnValue({
|
||||
// afterClosed$: of({} as UiModalResult<any>),
|
||||
// } as any);
|
||||
// });
|
||||
modalMock.open.and.returnValue({
|
||||
afterClosed$: of({} as UiModalResult<any>),
|
||||
} as any);
|
||||
});
|
||||
|
||||
// it('should be created', () => {
|
||||
// expect(httpErrorInterceptor).toBeTruthy();
|
||||
// });
|
||||
it('should be created', () => {
|
||||
expect(httpErrorInterceptor).toBeTruthy();
|
||||
});
|
||||
|
||||
// describe('intercept', () => {
|
||||
// it('should catch the error and call handleError', (done) => {
|
||||
// const error = new HttpErrorResponse({
|
||||
// status: 0,
|
||||
// statusText: '',
|
||||
// url: '',
|
||||
// });
|
||||
describe('intercept', () => {
|
||||
it('should catch the error and call handleError', (done) => {
|
||||
const error = new HttpErrorResponse({
|
||||
status: 0,
|
||||
statusText: '',
|
||||
url: '',
|
||||
});
|
||||
|
||||
// const handleErrorSpy = spyOn(httpErrorInterceptor, 'handleError').and.callThrough();
|
||||
// httpErrorInterceptor.intercept(null, { handle: () => throwError(error) }).subscribe({
|
||||
// error: () => {
|
||||
// expect(handleErrorSpy).toHaveBeenCalledWith(error);
|
||||
// done();
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
const handleErrorSpy = spyOn(httpErrorInterceptor, 'handleError').and.callThrough();
|
||||
httpErrorInterceptor.intercept(null, { handle: () => throwError(error) }).subscribe({
|
||||
error: () => {
|
||||
expect(handleErrorSpy).toHaveBeenCalledWith(error);
|
||||
done();
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// describe('handleError', () => {
|
||||
// it('should call modal.open with offline message if status is 0', () => {
|
||||
// const error = {
|
||||
// error: {
|
||||
// message: 'test',
|
||||
// },
|
||||
// status: 0,
|
||||
// };
|
||||
// httpErrorInterceptor.handleError(error as any);
|
||||
// expect(modalMock.open).toHaveBeenCalledWith({
|
||||
// content: UiMessageModalComponent,
|
||||
// title: 'Sie sind offline, keine Verbindung zum Netzwerk',
|
||||
// data: { message: 'Bereits geladene Inhalte werden angezeigt. Interaktionen sind aktuell nicht möglich.' },
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
describe('handleError', () => {
|
||||
it('should call modal.open with offline message if status is 0', () => {
|
||||
const error = {
|
||||
error: {
|
||||
message: 'test',
|
||||
},
|
||||
status: 0,
|
||||
};
|
||||
httpErrorInterceptor.handleError(error as any);
|
||||
expect(modalMock.open).toHaveBeenCalledWith({
|
||||
content: UiMessageModalComponent,
|
||||
title: 'Sie sind offline, keine Verbindung zum Netzwerk',
|
||||
data: { message: 'Bereits geladene Inhalte werden angezeigt. Interaktionen sind aktuell nicht möglich.' },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { inject, Injectable, Injector } from '@angular/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpInterceptor, HttpEvent, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http';
|
||||
import { from, NEVER, Observable, throwError } from 'rxjs';
|
||||
import { NEVER, Observable, throwError } from 'rxjs';
|
||||
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
import { catchError, filter, mergeMap, takeUntil, tap } from 'rxjs/operators';
|
||||
import { AuthService, LoginStrategy } from '@core/auth';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { IsaLogProvider } from '../providers';
|
||||
import { LogLevel } from '@core/logger';
|
||||
import { injectOnline$ } from '../services/network-status.service';
|
||||
@@ -11,7 +11,6 @@ import { injectOnline$ } from '../services/network-status.service';
|
||||
@Injectable()
|
||||
export class HttpErrorInterceptor implements HttpInterceptor {
|
||||
readonly offline$ = injectOnline$().pipe(filter((online) => !online));
|
||||
readonly injector = inject(Injector);
|
||||
|
||||
constructor(
|
||||
private _modal: UiModalService,
|
||||
@@ -28,9 +27,18 @@ export class HttpErrorInterceptor implements HttpInterceptor {
|
||||
|
||||
handleError(error: HttpErrorResponse): Observable<any> {
|
||||
if (error.status === 401) {
|
||||
const strategy = this.injector.get(LoginStrategy);
|
||||
|
||||
return from(strategy.login('Sie sind nicht mehr angemeldet')).pipe(mergeMap(() => NEVER));
|
||||
return this._modal
|
||||
.open({
|
||||
content: UiMessageModalComponent,
|
||||
title: 'Sie sind nicht mehr angemeldet',
|
||||
data: { message: 'Sie werden neu angemeldet' },
|
||||
})
|
||||
.afterClosed$.pipe(
|
||||
tap(() => {
|
||||
this._auth.login();
|
||||
}),
|
||||
mergeMap(() => NEVER),
|
||||
);
|
||||
}
|
||||
|
||||
if (!error.url.endsWith('/isa/logging')) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
selector: 'app-main',
|
||||
templateUrl: 'main.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: false,
|
||||
})
|
||||
export class MainComponent {
|
||||
constructor() {}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { Platform, PlatformModule } from '@angular/cdk/platform';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component } from '@angular/core';
|
||||
import { BranchDTO } from '@generated/swagger/checkout-api';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { BranchSelectorComponent } from '@shared/components/branch-selector';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-preview',
|
||||
templateUrl: 'preview.component.html',
|
||||
styleUrls: ['preview.component.css'],
|
||||
imports: [CommonModule, PlatformModule],
|
||||
imports: [CommonModule, BranchSelectorComponent, PlatformModule],
|
||||
standalone: true,
|
||||
})
|
||||
export class PreviewComponent {
|
||||
export class PreviewComponent implements OnInit {
|
||||
selectedBranch$ = new BehaviorSubject<BranchDTO>({});
|
||||
|
||||
get appVersion() {
|
||||
@@ -23,7 +25,7 @@ export class PreviewComponent {
|
||||
|
||||
get navigator() {
|
||||
const nav = {};
|
||||
for (const i in window.navigator) nav[i] = navigator[i];
|
||||
for (let i in window.navigator) nav[i] = navigator[i];
|
||||
return nav;
|
||||
}
|
||||
|
||||
@@ -50,6 +52,8 @@ export class PreviewComponent {
|
||||
|
||||
constructor(private readonly _platform: Platform) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
setNewBranch(branch: BranchDTO) {
|
||||
this.selectedBranch$.next(branch);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import { HttpErrorResponse } from "@angular/common/http";
|
||||
import { ErrorHandler, Injectable } from "@angular/core";
|
||||
import { AuthService } from "@core/auth";
|
||||
import {
|
||||
DialogModel,
|
||||
UiDialogModalComponent,
|
||||
UiErrorModalComponent,
|
||||
UiModalService,
|
||||
} from "@ui/modal";
|
||||
import { IsaLogProvider } from "./isa.log-provider";
|
||||
import { LogLevel } from "@core/logger";
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { ErrorHandler, Injectable } from '@angular/core';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { DialogModel, UiDialogModalComponent, UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { IsaLogProvider } from './isa.log-provider';
|
||||
import { LogLevel } from '@core/logger';
|
||||
|
||||
@Injectable({ providedIn: "root" })
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class IsaErrorHandler implements ErrorHandler {
|
||||
constructor(
|
||||
private _modal: UiModalService,
|
||||
@@ -22,7 +17,7 @@ export class IsaErrorHandler implements ErrorHandler {
|
||||
console.error(error);
|
||||
|
||||
// Bei Klick auf Abbrechen auf der Login Seite erneut zur Login Seite weiterleiten
|
||||
if (error?.type === "token_error") {
|
||||
if (error?.type === 'token_error') {
|
||||
this._authService.login();
|
||||
return;
|
||||
}
|
||||
@@ -31,14 +26,11 @@ export class IsaErrorHandler implements ErrorHandler {
|
||||
await this._modal
|
||||
.open({
|
||||
content: UiDialogModalComponent,
|
||||
title: "Sitzung abgelaufen",
|
||||
title: 'Sitzung abgelaufen',
|
||||
data: {
|
||||
handleCommand: false,
|
||||
content:
|
||||
"Sie waren zu lange nicht in der ISA aktiv. Bitte melden Sie sich erneut an",
|
||||
actions: [
|
||||
{ command: "CLOSE", selected: true, label: "Erneut anmelden" },
|
||||
],
|
||||
content: 'Sie waren zu lange nicht in der ISA aktiv. Bitte melden Sie sich erneut an',
|
||||
actions: [{ command: 'CLOSE', selected: true, label: 'Erneut anmelden' }],
|
||||
} as DialogModel,
|
||||
})
|
||||
.afterClosed$.toPromise();
|
||||
@@ -47,11 +39,7 @@ export class IsaErrorHandler implements ErrorHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this._isaLogProvider.log(LogLevel.ERROR, "Client Error", error);
|
||||
} catch (logError) {
|
||||
console.error("Error logging to IsaLogProvider:", logError);
|
||||
}
|
||||
this._isaLogProvider.log(LogLevel.ERROR, 'Client Error', error);
|
||||
|
||||
// this._modal.open({
|
||||
// content: UiErrorModalComponent,
|
||||
|
||||
@@ -1,36 +1,28 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { LogLevel, LogProvider } from "@core/logger";
|
||||
import { UserStateService } from "@generated/swagger/isa-api";
|
||||
import { environment } from "../../environments/environment";
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { LogLevel, LogProvider } from '@core/logger';
|
||||
import { UserStateService } from '@swagger/isa';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable({ providedIn: "root" })
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class IsaLogProvider implements LogProvider {
|
||||
static InfoService: UserStateService | undefined;
|
||||
|
||||
log(
|
||||
logLevel: LogLevel,
|
||||
message: string,
|
||||
error: Error,
|
||||
...optionalParams: any[]
|
||||
): void {
|
||||
try {
|
||||
if (
|
||||
!environment.production &&
|
||||
(logLevel === LogLevel.WARN || logLevel === LogLevel.ERROR)
|
||||
) {
|
||||
IsaLogProvider.InfoService?.UserStateSaveLog({
|
||||
logType: logLevel,
|
||||
message: message,
|
||||
content: JSON.stringify({
|
||||
error: error?.name,
|
||||
message: error?.message,
|
||||
stack: error?.stack,
|
||||
data: optionalParams,
|
||||
}),
|
||||
}).toPromise();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error logging to InfoService:", error);
|
||||
constructor() {}
|
||||
|
||||
log(logLevel: LogLevel, message: string, error: Error, ...optionalParams: any[]): void {
|
||||
if (!environment.production && (logLevel === LogLevel.WARN || logLevel === LogLevel.ERROR)) {
|
||||
IsaLogProvider.InfoService?.UserStateSaveLog({
|
||||
logType: logLevel,
|
||||
message: message,
|
||||
content: JSON.stringify({
|
||||
error: error?.name,
|
||||
message: error?.message,
|
||||
stack: error?.stack,
|
||||
data: optionalParams,
|
||||
}),
|
||||
})
|
||||
.toPromise()
|
||||
.catch(() => {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@ import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ProcessIdResolver {
|
||||
constructor() {}
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot): Observable<number> | Promise<number> | number {
|
||||
return route.params.processId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,7 @@ import { ApplicationService } from '@core/application';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export abstract class SectionResolver {
|
||||
constructor(
|
||||
protected section: 'customer' | 'branch',
|
||||
protected applicationService: ApplicationService,
|
||||
) {}
|
||||
constructor(protected section: 'customer' | 'branch', protected applicationService: ApplicationService) {}
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot): Observable<string> | Promise<string> | string {
|
||||
this.applicationService.setSection(this.section);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './network-status.service';
|
||||
@@ -1,32 +1,26 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Logger, LogLevel } from '@core/logger';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { UserStateService } from '@swagger/isa';
|
||||
import { debounceTime, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { RootState } from './root.state';
|
||||
import packageInfo from 'packageJson';
|
||||
import { environment } from '../../environments/environment';
|
||||
import { Subject } from 'rxjs';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { injectStorage, UserStorageProvider } from '@isa/core/storage';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class RootStateService {
|
||||
static LOCAL_STORAGE_KEY = 'ISA_APP_INITIALSTATE';
|
||||
|
||||
#storage = injectStorage(UserStorageProvider);
|
||||
|
||||
private _cancelSave = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private readonly _authService: AuthService,
|
||||
private readonly _userStateService: UserStateService,
|
||||
private _logger: Logger,
|
||||
private _store: Store,
|
||||
) {
|
||||
if (!environment.production) {
|
||||
console.log(
|
||||
'Die UserState kann in der Konsole mit der Funktion "clearUserState()" geleert werden.',
|
||||
);
|
||||
console.log('Die UserState kann in der Konsole mit der Funktion "clearUserState()" geleert werden.');
|
||||
}
|
||||
|
||||
window['clearUserState'] = () => {
|
||||
@@ -47,17 +41,9 @@ export class RootStateService {
|
||||
takeUntil(this._cancelSave),
|
||||
debounceTime(1000),
|
||||
switchMap((state) => {
|
||||
const data = {
|
||||
...state,
|
||||
version: packageInfo.version,
|
||||
sub: this._authService.getClaimByKey('sub'),
|
||||
};
|
||||
RootStateService.SaveToLocalStorageRaw(JSON.stringify(data));
|
||||
return this.#storage.set('state', {
|
||||
...state,
|
||||
version: packageInfo.version,
|
||||
sub: this._authService.getClaimByKey('sub'),
|
||||
});
|
||||
const raw = JSON.stringify({ ...state, version: packageInfo.version });
|
||||
RootStateService.SaveToLocalStorageRaw(raw);
|
||||
return this._userStateService.UserStateSetUserState({ content: raw });
|
||||
}),
|
||||
)
|
||||
.subscribe();
|
||||
@@ -68,15 +54,16 @@ export class RootStateService {
|
||||
*/
|
||||
async load(): Promise<boolean> {
|
||||
try {
|
||||
const res = await this.#storage.get('state');
|
||||
const res = await this._userStateService.UserStateGetUserState().toPromise();
|
||||
|
||||
const resContent = res?.result?.content ?? null;
|
||||
const storageContent = RootStateService.LoadFromLocalStorageRaw();
|
||||
|
||||
if (res) {
|
||||
RootStateService.SaveToLocalStorageRaw(JSON.stringify(res));
|
||||
if (resContent) {
|
||||
RootStateService.SaveToLocalStorageRaw(res.result.content);
|
||||
}
|
||||
|
||||
if (!isEqual(res, storageContent)) {
|
||||
if (resContent !== storageContent) {
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -88,7 +75,7 @@ export class RootStateService {
|
||||
async clear() {
|
||||
try {
|
||||
this._cancelSave.next();
|
||||
await this.#storage.clear('state');
|
||||
await this._userStateService.UserStateResetUserState().toPromise();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
RootStateService.RemoveFromLocalStorage();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
@@ -109,12 +96,7 @@ export class RootStateService {
|
||||
static LoadFromLocalStorage(): RootState {
|
||||
const raw = RootStateService.LoadFromLocalStorageRaw();
|
||||
if (raw) {
|
||||
try {
|
||||
return JSON.parse(raw);
|
||||
} catch (error) {
|
||||
console.error('Error parsing local storage:', error);
|
||||
this.RemoveFromLocalStorage();
|
||||
}
|
||||
return JSON.parse(raw);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -7,14 +7,9 @@ import { AuthService } from '@core/auth';
|
||||
templateUrl: 'token-login.component.html',
|
||||
styleUrls: ['token-login.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: false,
|
||||
})
|
||||
export class TokenLoginComponent implements OnInit {
|
||||
constructor(
|
||||
private _route: ActivatedRoute,
|
||||
private _authService: AuthService,
|
||||
private _router: Router,
|
||||
) {}
|
||||
constructor(private _route: ActivatedRoute, private _authService: AuthService, private _router: Router) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this._route.snapshot.params.token && !this._authService.isAuthenticated()) {
|
||||
|
||||
@@ -1,222 +1,219 @@
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-400-cyrillic-ext1.woff2") format("woff2");
|
||||
src: url('./Open_Sans-400-cyrillic-ext1.woff2') format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-400-cyrillic2.woff2") format("woff2");
|
||||
src: url('./Open_Sans-400-cyrillic2.woff2') format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-400-greek-ext3.woff2") format("woff2");
|
||||
src: url('./Open_Sans-400-greek-ext3.woff2') format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-400-greek4.woff2") format("woff2");
|
||||
src: url('./Open_Sans-400-greek4.woff2') format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* hebrew */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-400-hebrew5.woff2") format("woff2");
|
||||
src: url('./Open_Sans-400-hebrew5.woff2') format('woff2');
|
||||
unicode-range: U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-400-vietnamese6.woff2") format("woff2");
|
||||
src: url('./Open_Sans-400-vietnamese6.woff2') format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-400-latin-ext7.woff2") format("woff2");
|
||||
src: url('./Open_Sans-400-latin-ext7.woff2') format('woff2');
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-400-latin8.woff2") format("woff2");
|
||||
unicode-range:
|
||||
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
|
||||
U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
src: url('./Open_Sans-400-latin8.woff2') format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193,
|
||||
U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-600-cyrillic-ext9.woff2") format("woff2");
|
||||
src: url('./Open_Sans-600-cyrillic-ext9.woff2') format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-600-cyrillic10.woff2") format("woff2");
|
||||
src: url('./Open_Sans-600-cyrillic10.woff2') format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-600-greek-ext11.woff2") format("woff2");
|
||||
src: url('./Open_Sans-600-greek-ext11.woff2') format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-600-greek12.woff2") format("woff2");
|
||||
src: url('./Open_Sans-600-greek12.woff2') format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* hebrew */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-600-hebrew13.woff2") format("woff2");
|
||||
src: url('./Open_Sans-600-hebrew13.woff2') format('woff2');
|
||||
unicode-range: U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-600-vietnamese14.woff2") format("woff2");
|
||||
src: url('./Open_Sans-600-vietnamese14.woff2') format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-600-latin-ext15.woff2") format("woff2");
|
||||
src: url('./Open_Sans-600-latin-ext15.woff2') format('woff2');
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-600-latin16.woff2") format("woff2");
|
||||
unicode-range:
|
||||
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
|
||||
U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
src: url('./Open_Sans-600-latin16.woff2') format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193,
|
||||
U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-700-cyrillic-ext17.woff2") format("woff2");
|
||||
src: url('./Open_Sans-700-cyrillic-ext17.woff2') format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-700-cyrillic18.woff2") format("woff2");
|
||||
src: url('./Open_Sans-700-cyrillic18.woff2') format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-700-greek-ext19.woff2") format("woff2");
|
||||
src: url('./Open_Sans-700-greek-ext19.woff2') format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-700-greek20.woff2") format("woff2");
|
||||
src: url('./Open_Sans-700-greek20.woff2') format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* hebrew */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-700-hebrew21.woff2") format("woff2");
|
||||
src: url('./Open_Sans-700-hebrew21.woff2') format('woff2');
|
||||
unicode-range: U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-700-vietnamese22.woff2") format("woff2");
|
||||
src: url('./Open_Sans-700-vietnamese22.woff2') format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-700-latin-ext23.woff2") format("woff2");
|
||||
src: url('./Open_Sans-700-latin-ext23.woff2') format('woff2');
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-stretch: normal;
|
||||
src: url("./Open_Sans-700-latin24.woff2") format("woff2");
|
||||
unicode-range:
|
||||
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
|
||||
U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
src: url('./Open_Sans-700-latin24.woff2') format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193,
|
||||
U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
@@ -285,8 +285,27 @@
|
||||
"name": "gift",
|
||||
"data": "M2 21V10H0V4H5.2C5.11667 3.85 5.0625 3.69167 5.0375 3.525C5.0125 3.35833 5 3.18333 5 3C5 2.16667 5.29167 1.45833 5.875 0.875C6.45833 0.291667 7.16667 0 8 0C8.38333 0 8.74167 0.0708333 9.075 0.2125C9.40833 0.354167 9.71667 0.55 10 0.8C10.2833 0.533333 10.5917 0.333333 10.925 0.2C11.2583 0.0666667 11.6167 0 12 0C12.8333 0 13.5417 0.291667 14.125 0.875C14.7083 1.45833 15 2.16667 15 3C15 3.18333 14.9833 3.35417 14.95 3.5125C14.9167 3.67083 14.8667 3.83333 14.8 4H20V10H18V21H2ZM12 2C11.7167 2 11.4792 2.09583 11.2875 2.2875C11.0958 2.47917 11 2.71667 11 3C11 3.28333 11.0958 3.52083 11.2875 3.7125C11.4792 3.90417 11.7167 4 12 4C12.2833 4 12.5208 3.90417 12.7125 3.7125C12.9042 3.52083 13 3.28333 13 3C13 2.71667 12.9042 2.47917 12.7125 2.2875C12.5208 2.09583 12.2833 2 12 2ZM7 3C7 3.28333 7.09583 3.52083 7.2875 3.7125C7.47917 3.90417 7.71667 4 8 4C8.28333 4 8.52083 3.90417 8.7125 3.7125C8.90417 3.52083 9 3.28333 9 3C9 2.71667 8.90417 2.47917 8.7125 2.2875C8.52083 2.09583 8.28333 2 8 2C7.71667 2 7.47917 2.09583 7.2875 2.2875C7.09583 2.47917 7 2.71667 7 3ZM2 6V8H9V6H2ZM9 19V10H4V19H9ZM11 19H16V10H11V19ZM18 8V6H11V8H18Z",
|
||||
"viewBox": "0 0 20 21"
|
||||
},
|
||||
{
|
||||
"name": "undo",
|
||||
"data": "M280-200v-80h284q63 0 109.5-40T720-420q0-60-46.5-100T564-560H312l104 104-56 56-200-200 200-200 56 56-104 104h252q97 0 166.5 63T800-420q0 94-69.5 157T564-200H280Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
},
|
||||
{
|
||||
"name": "delete",
|
||||
"data": "M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
},
|
||||
{
|
||||
"name": "save",
|
||||
"data": "M840-680v480q0 33-23.5 56.5T760-120H200q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h480l160 160Zm-80 34L646-760H200v560h560v-446ZM480-240q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35ZM240-560h360v-160H240v160Zm-40-86v446-560 114Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
},
|
||||
{
|
||||
"name": "check",
|
||||
"data": "M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
}
|
||||
|
||||
],
|
||||
"aliases": [
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Directive, HostListener, inject, Input } from '@angular/core';
|
||||
import { Directive, HostListener, Input } from '@angular/core';
|
||||
import { ProductCatalogNavigationService } from '@shared/services/navigation';
|
||||
|
||||
@Directive({
|
||||
@@ -8,7 +8,7 @@ import { ProductCatalogNavigationService } from '@shared/services/navigation';
|
||||
export class NavigateOnClickDirective {
|
||||
@Input('productImageNavigation') ean: string;
|
||||
|
||||
private readonly _productCatalogNavigation = inject(ProductCatalogNavigationService);
|
||||
constructor(private readonly _productCatalogNavigation: ProductCatalogNavigationService) {}
|
||||
|
||||
@HostListener('click', ['$event'])
|
||||
async onClick(event: MouseEvent) {
|
||||
|
||||
@@ -1,85 +1,133 @@
|
||||
{
|
||||
"title": "ISA - Feature",
|
||||
"silentRefresh": {
|
||||
"interval": 300000
|
||||
},
|
||||
"@cdn/product-image": {
|
||||
"url": "https://produktbilder.paragon-data.net"
|
||||
},
|
||||
"@core/auth": {
|
||||
"issuer": "https://sso-test.paragon-data.de",
|
||||
"clientId": "hug-isa",
|
||||
"responseType": "id_token token",
|
||||
"oidc": true,
|
||||
"scope": "openid profile cmf_user isa-isa-webapi isa-checkout-webapi isa-cat-webapi isa-ava-webapi isa-crm-webapi isa-review-webapi isa-kpi-webapi isa-oms-webapi isa-nbo-webapi isa-print-webapi eis-service isa-inv-webapi isa-wws-webapi"
|
||||
},
|
||||
"@core/logger": {
|
||||
"logLevel": "debug"
|
||||
},
|
||||
"@domain/checkout": {
|
||||
"olaExpiration": "5m"
|
||||
},
|
||||
"@swagger/isa": {
|
||||
"rootUrl": "https://isa-feature.paragon-data.net/isa/v1"
|
||||
},
|
||||
"@swagger/cat": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/catsearch/v6"
|
||||
},
|
||||
"@swagger/av": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/ava/v6"
|
||||
},
|
||||
"@swagger/checkout": {
|
||||
"rootUrl": "https://isa-feature.paragon-data.net/checkout/v6"
|
||||
},
|
||||
"@swagger/crm": {
|
||||
"rootUrl": "https://isa-feature.paragon-data.net/crm/v6"
|
||||
},
|
||||
"@swagger/oms": {
|
||||
"rootUrl": "https://isa-feature.paragon-data.net/oms/v6"
|
||||
},
|
||||
"@swagger/print": {
|
||||
"rootUrl": "https://isa-feature.paragon-data.net/print/v1"
|
||||
},
|
||||
"@swagger/eis": {
|
||||
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
|
||||
},
|
||||
"@swagger/remi": {
|
||||
"rootUrl": "https://isa-feature.paragon-data.net/inv/v6"
|
||||
},
|
||||
"@swagger/wws": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"
|
||||
},
|
||||
"hubs": {
|
||||
"notifications": {
|
||||
"url": "https://isa-feature.paragon-data.net/isa/v1/rt",
|
||||
"enableAutomaticReconnect": false,
|
||||
"httpOptions": {
|
||||
"transport": 1,
|
||||
"logMessageContent": true,
|
||||
"skipNegotiation": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"process": {
|
||||
"ids": {
|
||||
"goodsOut": 1000,
|
||||
"goodsIn": 2000,
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000,
|
||||
"pickupShelf": 7000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "Ae8F2Wx2RMq5Lvn7UUAlWzVFZTt2+ubMAF8XtDpmPlNkBeG/LWs1M7AbgDW0LQqYLnszClEENaEHS56/6Ts2vrJ1Ux03CXUjK3jUvZpF5OchXR1CpnmpepJ6WxPCd7LMVHUGG1BbwPLDTFjP3y8uT0caTSmmGrYQWAs4CZcEF+ZBabP0z7vfm+hCZF/ebj9qqCJZcW8nH/n19hohshllzYBjFXjh87P2lIh1s6yZS3OaQWWXo/o0AKdxx7T6CVyR0/G5zq6uYJWf6rs3euUBEhpzOZHbHZK86Lvy2AVBEyVkkcttlDW1J2fA4l1W1JV/Xibz8AQV6kG482EpGF42KEoK48paZgX3e1AQsqUtmqzw294dcP4zMVstnw5/WrwKKi/5E/nOOJT2txYP1ZufIjPrwNFsqTlv7xCQlHjMzFGYwT816yD5qLRLbwOtjrkUPXNZLZ06T4upvWwJDmm8XgdeoDqMjHdcO4lwji1bl9EiIYJ/2qnsk9yZ2FqSaHzn4cbiL0f5u2HFlNAP0GUujGRlthGhHi6o4dFU+WAxKsFMKVt+SfoQUazNKHFVQgiAklTIZxIc/HUVzRvOLMxf+wFDerraBtcqGJg+g/5mrWYqeDBGhCBHtKiYf6244IJ4afzNTiH1/30SJcRzXwbEa3A7q1fJTx9/nLTOfVPrJKBQs7f/OQs2dA7LDCel8mzXdbjvsNQaeU5+iCIAq6zbTNKy1xT8wwj+VZrQmtNJs+qeznD+u29nCM24h8xCmRpvNPo4/Mww/lrTNrrNwLBSn1pMIwsH7yS9hH0v0oNAM3A6bVtk1D9qEkbyw+xZa+MZGpMP0D0CdcsqHalPcm5r/Ik="
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
"title": "ISA - Feature",
|
||||
"silentRefresh": {
|
||||
"interval": 300000
|
||||
},
|
||||
"@cdn/product-image": {
|
||||
"url": "https://produktbilder.paragon-data.net"
|
||||
},
|
||||
"@core/auth": {
|
||||
"issuer": "https://sso-test.paragon-data.de",
|
||||
"clientId": "hug-isa",
|
||||
"responseType": "id_token token",
|
||||
"oidc": true,
|
||||
"scope": "openid profile cmf_user isa-isa-webapi isa-checkout-webapi isa-cat-webapi isa-ava-webapi isa-crm-webapi isa-review-webapi isa-kpi-webapi isa-oms-webapi isa-nbo-webapi isa-print-webapi eis-service isa-inv-webapi isa-wws-webapi"
|
||||
},
|
||||
"@core/logger": {
|
||||
"logLevel": "debug"
|
||||
},
|
||||
"@domain/checkout": {
|
||||
"olaExpiration": "5m"
|
||||
},
|
||||
"@swagger/isa": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/isa/v1"
|
||||
},
|
||||
"@swagger/cat": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/catsearch/v6"
|
||||
},
|
||||
"@swagger/av": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/ava/v6"
|
||||
},
|
||||
"@swagger/checkout": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/checkout/v6"
|
||||
},
|
||||
"@swagger/crm": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/crm/v6"
|
||||
},
|
||||
"@swagger/oms": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/oms/v6"
|
||||
},
|
||||
"@swagger/print": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/print/v1"
|
||||
},
|
||||
"@swagger/eis": {
|
||||
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
|
||||
},
|
||||
"@swagger/remi": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/inv/v6"
|
||||
},
|
||||
"@swagger/wws": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"
|
||||
},
|
||||
"hubs": {
|
||||
"notifications": {
|
||||
"url": "https://isa-test.paragon-data.net/isa/v1/rt",
|
||||
"enableAutomaticReconnect": false,
|
||||
"httpOptions": {
|
||||
"transport": 1,
|
||||
"logMessageContent": true,
|
||||
"skipNegotiation": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"process": {
|
||||
"ids": {
|
||||
"goodsOut": 1000,
|
||||
"goodsIn": 2000,
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000,
|
||||
"pickupShelf": 7000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "Ac2kvx5ZOzjvFl/LuAd6wds3C30YJ4g8Cm6PX4sgUnKPePVMuH+rFQIyVNn1YdS3myORojEOBsIZWhMw2nRUGBtOnQ5FO+cRHgQu0pkP+VG6OYvt8ETUTn8Aa2f9bmfqclO3LI8WN8psWr+adkZEtqNTvCgyDLZaICh8S7RfmwJVVWaOPX4LDagGhLDPS2YQdg+ibpR0l0ZlX2h/3GttofE64HOlBN3QtDB8yihHJNgVcUVy2UQVS+BXOyvIfZEFbFgPYVt5HZ0aQgcISlYVAmJvRsHyeKYRUnIi3ZN73EQmHzWcOV4/HWVoTs1MTW0mxV074vNwqExYW9LYmz9zgLUD7FMnKMFClkzRBHRN1CC7brosCnFkZWQp3CV4Ua48Fn9GW0Zpn/4MIZgzSU26inl5ZnT3dCc2+3BH3Us1uugTUrOPwFuwsPpr4NZYXWJMOmcm4kBBVJd0Uwk28GyZM7x1hXADcQgcc23+gDtbbUZWVmr3TE7GBcV3j+XUeOk8nHZw3DsYJ46MT2sSfks3QXRl4tBkBad6M+UxW4tb2IQC/4K9IXKhDN8VYXpzrrRHJNvOiH5+NrixthDZHHd/MGNuBDrJFOuXq8L7O6PxBoVZ0NPXmCO5vKyYdhBz5gJ5u3vNkSke7p+cDcvFicsVyNWRaaoFL0UN9gxFVMY8hkJKBZyGxZL2LEDXD44PxPsDnygpDC1Jyc7pkhEA0fKSc9aXZb1HDpwe1hqyyRVBtHkgPiN78GmJImbaUlj8XsK3yVyAjs2XvPR0/3ASHS53ViwzWKL3Oi8I515IJDtDhlvrkeh7MrWMaEu9k6ZQXJi1uJsh3JGfyS+yDlPjePVdsVqnZ4uw9pKMXvjlJeNcIiGM2Cf5S89nk2Qe/56MrKB9Frm6Q5wQHai8TNdCZYBi67dmAX8KHPXvEU4K6KyyW89YGcabZQ3eOJDr4oqW9ZcYPBttREdH3WI/HxvpEq6bqoDhT9AxpIWEMVb6y/DcDHSEresepibug4qOr9xOPq0yk2uiWYhPubFnCk7thQCXOGv9crWnQoOrt9c1qoaWXM4YmKqfcaQ67Tn+uFQmYTZyqw4jlJU4GgKe5/GNCVQM5aNUg1J0Px1NlFCS+rrIDyMQp0byFcgTd/E9sA5d1+YZKHKmJiQwEAz6oU9yyoUlxntSI42GHB/UttPc7Hj14V5+oJ+Yz+CZodmkXFg57Vx4NuxveNtO"
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
"paymentStatus": {
|
||||
"0": "-",
|
||||
"1": "ProformaInvoicePrinted",
|
||||
"2": "InvoicePrinted",
|
||||
"4": "Bezahlt",
|
||||
"8": "OnApproval",
|
||||
"16": "Kostenlos",
|
||||
"32": "Mahnung",
|
||||
"64": "ProformaInvoicePaid",
|
||||
"128": "Canceled",
|
||||
"256": "Mahnung",
|
||||
"512": "PartiallyPaid",
|
||||
"1024": "Outstanding"
|
||||
},
|
||||
"paymentType": {
|
||||
"0": "-",
|
||||
"1": "WhenCollecting",
|
||||
"2": "Kostenlos",
|
||||
"4": "Bar",
|
||||
"8": "DirectDebit",
|
||||
"16": "DebitAdviceMandate",
|
||||
"32": "DebitCard",
|
||||
"64": "Kreditkarte",
|
||||
"128": "Rechnung",
|
||||
"256": "Vorkasse",
|
||||
"512": "Voucher",
|
||||
"1024": "CollectiveInvoice",
|
||||
"2048": "PayPal",
|
||||
"4096": "InstantTransfer",
|
||||
"8192": "BonusCard",
|
||||
"16384": "AmazonPay"
|
||||
},
|
||||
"receiptType": {
|
||||
"0": "-",
|
||||
"1": "Lieferschein",
|
||||
"2": "Gutschrift",
|
||||
"4": "Sammelgutschrift",
|
||||
"8": "CollectiveCreditNote",
|
||||
"16": "Sammellieferschein für Kundenkartenkäufe",
|
||||
"32": "Sammelgutschrift für Kundenkartenkäufe",
|
||||
"64": "Zahlungsbeleg",
|
||||
"128": "Rechnung",
|
||||
"256": "Sammelrechnung",
|
||||
"512": "Proformarechnung / Vorauskasse",
|
||||
"1024": "Bon/Quittung",
|
||||
"2048": "Rücknahmebeleg"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
},
|
||||
"@domain/checkout": {
|
||||
"olaExpiration": "5m"
|
||||
},
|
||||
},
|
||||
"@swagger/isa": {
|
||||
"rootUrl": "https://isa-integration.paragon-data.net/isa/v1"
|
||||
},
|
||||
@@ -72,13 +72,60 @@
|
||||
},
|
||||
"checkForUpdates": 900000,
|
||||
"licence": {
|
||||
"scandit": "ASq1ZCbuDs0nJ4cPGkFOSkQEBHSL/kuljVAq2ttwz2Q5CEwULWAlasJIkjsIe/nptzNx1IBSxwDPWh0gXmvF08BRBDTzDUELdX6q02N/HUddSHE4A1dMXoFg+I8of+iZQijQIogxmP5RfSpj6ixzD2cGV0w+BG6o9xRXG4lEv9vNAOC3+emfcuVj2Whmfbuzao4HcWweVSz4HJh8dcbxTPF10MH8qR4kkV7fNWIF+PaYww69relfuvrkgdbWPcLs4Xb7WW4AISX9pTmJmSuv2LvD9gMoPNlmhdTWi+qFcmgZiPRDb1I0Bldo7jKLdboylEXkVQVWF1D2fv3iO5BrijG+n52XQd3ew49/1ssJi6dWhxiZQMlN+mz7cfSPmGzJc0eqaf52tEA8PkIupXjly/6dckSVcqTsex+wHcQuTinyW2bu9/YY3ZTMCp5du+lFZBD+AQSsq7EALzzithpijNG3jQka/8yRSHPBP6JtfobMdbv7SlAESslnN5R5lKJms4HnSm4CwxBAX2sUrhQeuit74/5pwe8qI+CaEGzjKYfmcRhFXd+Kz/ySV3HyrVuieH6+6ytBjGh3EkwGvQ8Ovu4KsruWAyAjHwRyBdrFIRYyLWdou77VH8gSLwHi69QsMGshcnYaREpqDEb5LLR9Ok7jP5IjMyPzX4USS327G9f4I8ujTaCKXQ9a384yV/wP9IeSuJld4dgdGy80rDP2sWZ+NJ65cNWpAfi/Nmbm6ucjICoUHILtchyx/w/YNYUzfCWFjUWHn83TzG+31f3dkjWoI3XpCOg5RKREs55htHSAyZtYhYiQr1FxDVFNEQI2MrDR0fBt2qOeZB08yA=="
|
||||
"scandit": "Ac2kvx5ZOzjvFl/LuAd6wds3C30YJ4g8Cm6PX4sgUnKPePVMuH+rFQIyVNn1YdS3myORojEOBsIZWhMw2nRUGBtOnQ5FO+cRHgQu0pkP+VG6OYvt8ETUTn8Aa2f9bmfqclO3LI8WN8psWr+adkZEtqNTvCgyDLZaICh8S7RfmwJVVWaOPX4LDagGhLDPS2YQdg+ibpR0l0ZlX2h/3GttofE64HOlBN3QtDB8yihHJNgVcUVy2UQVS+BXOyvIfZEFbFgPYVt5HZ0aQgcISlYVAmJvRsHyeKYRUnIi3ZN73EQmHzWcOV4/HWVoTs1MTW0mxV074vNwqExYW9LYmz9zgLUD7FMnKMFClkzRBHRN1CC7brosCnFkZWQp3CV4Ua48Fn9GW0Zpn/4MIZgzSU26inl5ZnT3dCc2+3BH3Us1uugTUrOPwFuwsPpr4NZYXWJMOmcm4kBBVJd0Uwk28GyZM7x1hXADcQgcc23+gDtbbUZWVmr3TE7GBcV3j+XUeOk8nHZw3DsYJ46MT2sSfks3QXRl4tBkBad6M+UxW4tb2IQC/4K9IXKhDN8VYXpzrrRHJNvOiH5+NrixthDZHHd/MGNuBDrJFOuXq8L7O6PxBoVZ0NPXmCO5vKyYdhBz5gJ5u3vNkSke7p+cDcvFicsVyNWRaaoFL0UN9gxFVMY8hkJKBZyGxZL2LEDXD44PxPsDnygpDC1Jyc7pkhEA0fKSc9aXZb1HDpwe1hqyyRVBtHkgPiN78GmJImbaUlj8XsK3yVyAjs2XvPR0/3ASHS53ViwzWKL3Oi8I515IJDtDhlvrkeh7MrWMaEu9k6ZQXJi1uJsh3JGfyS+yDlPjePVdsVqnZ4uw9pKMXvjlJeNcIiGM2Cf5S89nk2Qe/56MrKB9Frm6Q5wQHai8TNdCZYBi67dmAX8KHPXvEU4K6KyyW89YGcabZQ3eOJDr4oqW9ZcYPBttREdH3WI/HxvpEq6bqoDhT9AxpIWEMVb6y/DcDHSEresepibug4qOr9xOPq0yk2uiWYhPubFnCk7thQCXOGv9crWnQoOrt9c1qoaWXM4YmKqfcaQ67Tn+uFQmYTZyqw4jlJU4GgKe5/GNCVQM5aNUg1J0Px1NlFCS+rrIDyMQp0byFcgTd/E9sA5d1+YZKHKmJiQwEAz6oU9yyoUlxntSI42GHB/UttPc7Hj14V5+oJ+Yz+CZodmkXFg57Vx4NuxveNtO"
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
},
|
||||
"paymentStatus": {
|
||||
"0": "-",
|
||||
"1": "ProformaInvoicePrinted",
|
||||
"2": "InvoicePrinted",
|
||||
"4": "Bezahlt",
|
||||
"8": "OnApproval",
|
||||
"16": "Kostenlos",
|
||||
"32": "Mahnung",
|
||||
"64": "ProformaInvoicePaid",
|
||||
"128": "Canceled",
|
||||
"256": "Mahnung",
|
||||
"512": "PartiallyPaid",
|
||||
"1024": "Outstanding"
|
||||
},
|
||||
"paymentType": {
|
||||
"0": "-",
|
||||
"1": "WhenCollecting",
|
||||
"2": "Kostenlos",
|
||||
"4": "Bar",
|
||||
"8": "DirectDebit",
|
||||
"16": "DebitAdviceMandate",
|
||||
"32": "DebitCard",
|
||||
"64": "Kreditkarte",
|
||||
"128": "Rechnung",
|
||||
"256": "Vorkasse",
|
||||
"512": "Voucher",
|
||||
"1024": "CollectiveInvoice",
|
||||
"2048": "PayPal",
|
||||
"4096": "InstantTransfer",
|
||||
"8192": "BonusCard",
|
||||
"16384": "AmazonPay"
|
||||
},
|
||||
"receiptType": {
|
||||
"0": "-",
|
||||
"1": "Lieferschein",
|
||||
"2": "Gutschrift",
|
||||
"4": "Sammelgutschrift",
|
||||
"8": "CollectiveCreditNote",
|
||||
"16": "Sammellieferschein für Kundenkartenkäufe",
|
||||
"32": "Sammelgutschrift für Kundenkartenkäufe",
|
||||
"64": "Zahlungsbeleg",
|
||||
"128": "Rechnung",
|
||||
"256": "Sammelrechnung",
|
||||
"512": "Proformarechnung / Vorauskasse",
|
||||
"1024": "Bon/Quittung",
|
||||
"2048": "Rücknahmebeleg"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
}
|
||||
@@ -1,87 +1,133 @@
|
||||
{
|
||||
"title": "ISA - Local",
|
||||
"silentRefresh": {
|
||||
"interval": 300000
|
||||
},
|
||||
"debug": true,
|
||||
"dev-scanner": true,
|
||||
"@cdn/product-image": {
|
||||
"url": "https://produktbilder.paragon-data.net"
|
||||
},
|
||||
"@core/auth": {
|
||||
"issuer": "https://sso-test.paragon-data.de",
|
||||
"clientId": "isa-client",
|
||||
"responseType": "code",
|
||||
"scope": "openid profile cmf_user isa-isa-webapi isa-checkout-webapi isa-cat-webapi isa-ava-webapi isa-crm-webapi isa-review-webapi isa-kpi-webapi isa-oms-webapi isa-nbo-webapi isa-print-webapi eis-service isa-inv-webapi isa-wws-webapi",
|
||||
"showDebugInformation": true
|
||||
},
|
||||
"@core/logger": {
|
||||
"logLevel": "debug"
|
||||
},
|
||||
"@swagger/isa": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/isa/v1"
|
||||
},
|
||||
"@swagger/cat": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/catsearch/v6"
|
||||
},
|
||||
"@swagger/av": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/ava/v6"
|
||||
},
|
||||
"@swagger/checkout": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/checkout/v6"
|
||||
},
|
||||
"@swagger/crm": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/crm/v6"
|
||||
},
|
||||
"@swagger/oms": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/oms/v6"
|
||||
},
|
||||
"@swagger/print": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/print/v1"
|
||||
},
|
||||
"@swagger/eis": {
|
||||
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
|
||||
},
|
||||
"@swagger/remi": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/inv/v6"
|
||||
},
|
||||
"@swagger/wws": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"
|
||||
},
|
||||
"@domain/checkout": {
|
||||
"olaExpiration": "5m"
|
||||
},
|
||||
"hubs": {
|
||||
"notifications": {
|
||||
"url": "https://isa-test.paragon-data.net/isa/v1/rt",
|
||||
"enableAutomaticReconnect": false,
|
||||
"httpOptions": {
|
||||
"transport": 1,
|
||||
"logMessageContent": true,
|
||||
"skipNegotiation": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"process": {
|
||||
"ids": {
|
||||
"goodsOut": 1000,
|
||||
"goodsIn": 2000,
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000,
|
||||
"pickupShelf": 7000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "Ae8F2Wx2RMq5Lvn7UUAlWzVFZTt2+ubMAF8XtDpmPlNkBeG/LWs1M7AbgDW0LQqYLnszClEENaEHS56/6Ts2vrJ1Ux03CXUjK3jUvZpF5OchXR1CpnmpepJ6WxPCd7LMVHUGG1BbwPLDTFjP3y8uT0caTSmmGrYQWAs4CZcEF+ZBabP0z7vfm+hCZF/ebj9qqCJZcW8nH/n19hohshllzYBjFXjh87P2lIh1s6yZS3OaQWWXo/o0AKdxx7T6CVyR0/G5zq6uYJWf6rs3euUBEhpzOZHbHZK86Lvy2AVBEyVkkcttlDW1J2fA4l1W1JV/Xibz8AQV6kG482EpGF42KEoK48paZgX3e1AQsqUtmqzw294dcP4zMVstnw5/WrwKKi/5E/nOOJT2txYP1ZufIjPrwNFsqTlv7xCQlHjMzFGYwT816yD5qLRLbwOtjrkUPXNZLZ06T4upvWwJDmm8XgdeoDqMjHdcO4lwji1bl9EiIYJ/2qnsk9yZ2FqSaHzn4cbiL0f5u2HFlNAP0GUujGRlthGhHi6o4dFU+WAxKsFMKVt+SfoQUazNKHFVQgiAklTIZxIc/HUVzRvOLMxf+wFDerraBtcqGJg+g/5mrWYqeDBGhCBHtKiYf6244IJ4afzNTiH1/30SJcRzXwbEa3A7q1fJTx9/nLTOfVPrJKBQs7f/OQs2dA7LDCel8mzXdbjvsNQaeU5+iCIAq6zbTNKy1xT8wwj+VZrQmtNJs+qeznD+u29nCM24h8xCmRpvNPo4/Mww/lrTNrrNwLBSn1pMIwsH7yS9hH0v0oNAM3A6bVtk1D9qEkbyw+xZa+MZGpMP0D0CdcsqHalPcm5r/Ik="
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
"title": "ISA - Local",
|
||||
"silentRefresh": {
|
||||
"interval": 300000
|
||||
},
|
||||
"debug": true,
|
||||
"@cdn/product-image": {
|
||||
"url": "https://produktbilder.paragon-data.net"
|
||||
},
|
||||
"@core/auth": {
|
||||
"issuer": "https://sso-test.paragon-data.de",
|
||||
"clientId": "isa-client",
|
||||
"responseType": "code",
|
||||
"scope": "openid profile cmf_user isa-isa-webapi isa-checkout-webapi isa-cat-webapi isa-ava-webapi isa-crm-webapi isa-review-webapi isa-kpi-webapi isa-oms-webapi isa-nbo-webapi isa-print-webapi eis-service isa-inv-webapi isa-wws-webapi",
|
||||
"showDebugInformation": true
|
||||
},
|
||||
"@core/logger": {
|
||||
"logLevel": "debug"
|
||||
},
|
||||
"@swagger/isa": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/isa/v1"
|
||||
},
|
||||
"@swagger/cat": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/catsearch/v6"
|
||||
},
|
||||
"@swagger/av": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/ava/v6"
|
||||
},
|
||||
"@swagger/checkout": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/checkout/v6"
|
||||
},
|
||||
"@swagger/crm": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/crm/v6"
|
||||
},
|
||||
"@swagger/oms": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/oms/v6"
|
||||
},
|
||||
"@swagger/print": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/print/v1"
|
||||
},
|
||||
"@swagger/eis": {
|
||||
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
|
||||
},
|
||||
"@swagger/remi": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/inv/v6"
|
||||
},
|
||||
"@swagger/wws": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"
|
||||
},
|
||||
"@domain/checkout": {
|
||||
"olaExpiration": "5m"
|
||||
},
|
||||
"hubs": {
|
||||
"notifications": {
|
||||
"url": "https://isa-test.paragon-data.net/isa/v1/rt",
|
||||
"enableAutomaticReconnect": false,
|
||||
"httpOptions": {
|
||||
"transport": 1,
|
||||
"logMessageContent": true,
|
||||
"skipNegotiation": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"process": {
|
||||
"ids": {
|
||||
"goodsOut": 1000,
|
||||
"goodsIn": 2000,
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000,
|
||||
"pickupShelf": 7000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "Ac2kvx5ZOzjvFl/LuAd6wds3C30YJ4g8Cm6PX4sgUnKPePVMuH+rFQIyVNn1YdS3myORojEOBsIZWhMw2nRUGBtOnQ5FO+cRHgQu0pkP+VG6OYvt8ETUTn8Aa2f9bmfqclO3LI8WN8psWr+adkZEtqNTvCgyDLZaICh8S7RfmwJVVWaOPX4LDagGhLDPS2YQdg+ibpR0l0ZlX2h/3GttofE64HOlBN3QtDB8yihHJNgVcUVy2UQVS+BXOyvIfZEFbFgPYVt5HZ0aQgcISlYVAmJvRsHyeKYRUnIi3ZN73EQmHzWcOV4/HWVoTs1MTW0mxV074vNwqExYW9LYmz9zgLUD7FMnKMFClkzRBHRN1CC7brosCnFkZWQp3CV4Ua48Fn9GW0Zpn/4MIZgzSU26inl5ZnT3dCc2+3BH3Us1uugTUrOPwFuwsPpr4NZYXWJMOmcm4kBBVJd0Uwk28GyZM7x1hXADcQgcc23+gDtbbUZWVmr3TE7GBcV3j+XUeOk8nHZw3DsYJ46MT2sSfks3QXRl4tBkBad6M+UxW4tb2IQC/4K9IXKhDN8VYXpzrrRHJNvOiH5+NrixthDZHHd/MGNuBDrJFOuXq8L7O6PxBoVZ0NPXmCO5vKyYdhBz5gJ5u3vNkSke7p+cDcvFicsVyNWRaaoFL0UN9gxFVMY8hkJKBZyGxZL2LEDXD44PxPsDnygpDC1Jyc7pkhEA0fKSc9aXZb1HDpwe1hqyyRVBtHkgPiN78GmJImbaUlj8XsK3yVyAjs2XvPR0/3ASHS53ViwzWKL3Oi8I515IJDtDhlvrkeh7MrWMaEu9k6ZQXJi1uJsh3JGfyS+yDlPjePVdsVqnZ4uw9pKMXvjlJeNcIiGM2Cf5S89nk2Qe/56MrKB9Frm6Q5wQHai8TNdCZYBi67dmAX8KHPXvEU4K6KyyW89YGcabZQ3eOJDr4oqW9ZcYPBttREdH3WI/HxvpEq6bqoDhT9AxpIWEMVb6y/DcDHSEresepibug4qOr9xOPq0yk2uiWYhPubFnCk7thQCXOGv9crWnQoOrt9c1qoaWXM4YmKqfcaQ67Tn+uFQmYTZyqw4jlJU4GgKe5/GNCVQM5aNUg1J0Px1NlFCS+rrIDyMQp0byFcgTd/E9sA5d1+YZKHKmJiQwEAz6oU9yyoUlxntSI42GHB/UttPc7Hj14V5+oJ+Yz+CZodmkXFg57Vx4NuxveNtO"
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
"paymentStatus": {
|
||||
"0": "-",
|
||||
"1": "ProformaInvoicePrinted",
|
||||
"2": "InvoicePrinted",
|
||||
"4": "Bezahlt",
|
||||
"8": "OnApproval",
|
||||
"16": "Kostenlos",
|
||||
"32": "Mahnung",
|
||||
"64": "ProformaInvoicePaid",
|
||||
"128": "Canceled",
|
||||
"256": "Mahnung",
|
||||
"512": "PartiallyPaid",
|
||||
"1024": "Outstanding"
|
||||
},
|
||||
"paymentType": {
|
||||
"0": "-",
|
||||
"1": "WhenCollecting",
|
||||
"2": "Kostenlos",
|
||||
"4": "Bar",
|
||||
"8": "DirectDebit",
|
||||
"16": "DebitAdviceMandate",
|
||||
"32": "DebitCard",
|
||||
"64": "Kreditkarte",
|
||||
"128": "Rechnung",
|
||||
"256": "Vorkasse",
|
||||
"512": "Voucher",
|
||||
"1024": "CollectiveInvoice",
|
||||
"2048": "PayPal",
|
||||
"4096": "InstantTransfer",
|
||||
"8192": "BonusCard",
|
||||
"16384": "AmazonPay"
|
||||
},
|
||||
"receiptType": {
|
||||
"0": "-",
|
||||
"1": "Lieferschein",
|
||||
"2": "Gutschrift",
|
||||
"4": "Sammelgutschrift",
|
||||
"8": "CollectiveCreditNote",
|
||||
"16": "Sammellieferschein für Kundenkartenkäufe",
|
||||
"32": "Sammelgutschrift für Kundenkartenkäufe",
|
||||
"64": "Zahlungsbeleg",
|
||||
"128": "Rechnung",
|
||||
"256": "Sammelrechnung",
|
||||
"512": "Proformarechnung / Vorauskasse",
|
||||
"1024": "Bon/Quittung",
|
||||
"2048": "Rücknahmebeleg"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -73,7 +73,7 @@
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "ATSVF4WBEUdWFabwSBws+xhCeCSCzgKZVEUjDXt0v6EpJHyN7lNmjMNmg8S+ADBh6h/Wn6Vl1b8TDhw3Fl1ZdkFoQ88zZUgagRY9vKpAjzimETtcVmzAA05W498GYgSr42+q4P9dkGO1RPdcOXqAgZZpNlsaQnyP1WjOMvgRRouwBxnoVCwkir8//kLxJaHPJKSYQNcTdRNMgqNPq/vUwdYVrzg26ltn7eC5imeXyYuQH3u2L4TVuRjr3SDVqsv7lnybh3ijg3dLoI93atUBuxbmzvoWzyb2mxrchJ9DaxrBy0igV2qFzzF1R6QvlNTyvN9HyUvZ0/sPS1DqOoql9bqG7ibyGOdRa2/vfIDTLbVEIaym8yQzErBBqthjviCub2pYXGX+ai9xXufuqRDyX29uCafxSv6sQsnVcEnuLEmP6gdmGBMVvH/WEZHnGn6bQpfWwFIGRZZKM+SxTdToJanj3jxNF/pO445/YZWJBDRT5nP55gESsrwiTXbb+i9lY4Hx7srEQJR07lJWASfKGX6IJtUaIstl7KnO6VI72XI2Zo01SAQAOw7m5+70LgYN1woYoAcziCSFyuIfJavGF0zd1cAu95Cwo0E8+y/YcAO3jwEqFE8oH7PkqKEf4XbF166quTf3AmVQJ8Q6lfSqWlZTps/dDGCAOe3Z63drIbh2bu3A/49bjT1TS7RFK5QvkKCtrM8zOS1DhEDjPPNR84BD/vbpjehHUlG6i7xlTwhmYblQR1oMUpfqrHqX5b9Lg2qADH+AfKRJ7Xd/kPSXdEw7MvJaZFpv9VuiFlUv37EyQBopyFhWYxRU9Kb1XfmkxpO+TCovzmEbKpWxi8KBYOdbX3QaNBW6HQLEd79+H8E="
|
||||
"scandit": "AZ70hgtZLmFWHbYP+BDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YfzKaR2xbfjsImjXJN7C/TE1CYXsv3DeqIzgDRA/kII4LzqoICWm9mnwejER1kMu1Vf+1NWbwUuYJjsQVQXYkwkWgnv53obevBZtjpgZqIzlStufIU+sPNEWSd9BlrLmiSEu6nXC5lbstyPJVaqihsFoBPNJ0Q+IgJUjqaxhTf6hGtNB3Rqcpv0ZT349NdK9mQ+9lAQYCwXdmYbELdlbZVSja0aJQlkf0TaAjixDbNcR32/VMIw98F2YxVRVWPnADUaJ9Bn8oa7NkOJIUfB7VAg1KtUl8IIwSXvRk436UtPZGxg+PQM7UXX/TgiBuqCQWdUChoH/QAoY2fyKRKgXJHnGdt+pBRQ2OYs7TZWCJLZsLKgnHV+eWh3Y3EB1hN9cmcszdnmYiyD1gCY8pSETFbWV01nVPvIuUTc+jMipv3NN81VQDS5/eU1VJNpRuDiufdBKJv0jjHQk+hTdqe+2GSmMD24ZG8FQXJZZPBCodWR1A81T8toCaIAGHnOfZeO7nxZu9Uo+6ohrVxc5F4szSizra+M3zfuFnm5FGgxCKt5uibLYgRyNcmR8/9vqTfMZgalTklbKHEFw1i+xOwrFrqRMh7FoovDRoI3QuaHLpV+ZUpZo3zTOQofdXPthKAmSLc11cjn509oTnnXUBBoBn/hErrwC/v8dZep1YEKM3wjfuIFsHRrsECswqNjwN/yOZCirm2VvFJEPMuKIwy+8jdNGncm8v4R9Br3c+wYJ8696L7Dg0iFShoyoP4OqIvBNY+dYyy935yGkIF2KI6l01xQZcWoHSVKPd6/78Iwy4lTKhtOqtu7ETJqOE53gQpR9jaAY0RiBB1SLm+Jbwt3ipSJiCDgKmkVmk5AU9HC0XYR/erjg13HF4hIcpLPW1ZWMKSxTqZ8z8FMJilInBgfcBwvjNE5seWvdFKltvlItnGhSh7BLUZ5UInDhl00NJBE2PdstDvRvQjLKvYUoFly3jONVsUfuQpzrcjT0g6gEgL8ZtlmaF11owcCvqhNDxWuTAJTX/xXf6WehxEB0qy3xCdxahbuneS3DPI0z2kAQwrx19i5r+RKQ8bWDaQ/OGY47sLPJgDgijEz16CvAMBSN0PvOso6FstsT/ynR3LLTPcY0QDw21Dv3wNHNa9HbanJcb3/MuhZGlrKp7"
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
@@ -81,5 +81,52 @@
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
"paymentStatus": {
|
||||
"0": "-",
|
||||
"1": "ProformaInvoicePrinted",
|
||||
"2": "InvoicePrinted",
|
||||
"4": "Bezahlt",
|
||||
"8": "OnApproval",
|
||||
"16": "Kostenlos",
|
||||
"32": "Mahnung",
|
||||
"64": "ProformaInvoicePaid",
|
||||
"128": "Canceled",
|
||||
"256": "Mahnung",
|
||||
"512": "PartiallyPaid",
|
||||
"1024": "Outstanding"
|
||||
},
|
||||
"paymentType": {
|
||||
"0": "-",
|
||||
"1": "WhenCollecting",
|
||||
"2": "Kostenlos",
|
||||
"4": "Bar",
|
||||
"8": "DirectDebit",
|
||||
"16": "DebitAdviceMandate",
|
||||
"32": "DebitCard",
|
||||
"64": "Kreditkarte",
|
||||
"128": "Rechnung",
|
||||
"256": "Vorkasse",
|
||||
"512": "Voucher",
|
||||
"1024": "CollectiveInvoice",
|
||||
"2048": "PayPal",
|
||||
"4096": "InstantTransfer",
|
||||
"8192": "BonusCard",
|
||||
"16384": "AmazonPay"
|
||||
},
|
||||
"receiptType": {
|
||||
"0": "-",
|
||||
"1": "Lieferschein",
|
||||
"2": "Gutschrift",
|
||||
"4": "Sammelgutschrift",
|
||||
"8": "CollectiveCreditNote",
|
||||
"16": "Sammellieferschein für Kundenkartenkäufe",
|
||||
"32": "Sammelgutschrift für Kundenkartenkäufe",
|
||||
"64": "Zahlungsbeleg",
|
||||
"128": "Rechnung",
|
||||
"256": "Sammelrechnung",
|
||||
"512": "Proformarechnung / Vorauskasse",
|
||||
"1024": "Bon/Quittung",
|
||||
"2048": "Rücknahmebeleg"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -73,13 +73,60 @@
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AbBVKBt1M6NjGVMLDyT7EBwD7Baj5eMzG0k8HT1QSQbUGAFCXXqF73RfxM88FluMPljT8WdVsHkvZcnrZmRhLRVGTU4rclBlVWYck0VozFbIbERw0GyFytcpKt78WTqihXGIkZFEoxcPH5YU63s1x/NDYJMYVvoT3CX+jYl/wGmLOSs/uH8u8p9wpNbjBx3IF0Yu6CA+gGDFP8RngRoRZtBvaLU4IEdk30Ehmg8iCso2Wl+8ePGYgRL+JndZ9B7ZI0lw2YBdsoCoPAVEUB0Ta1osx3rZ9eAmCSLlpCbJtDspHPqVFiQ6a2eBV9Wl5YZ2qrW8NYZ5GntJfytySqka9kOu3nubq04UMuZ6KyNkXjlUO1OvlFYBYW7eudeGParR1iJLPZMghJBOiWPv3nHMxWyxOXhZQKr1zhYgolbceOClnmIPF4JdDgpCwe4RdPTggYTU2Jh1YgPj67tNbijj8OtH7xMpALEOBAJ1/z6zNkYtLAS0qcwzH+QWwSC+I7vP1ne//ODsHLToUbe2LJoUEEht74NPTLWaLMTmmtfPrcoXSQX23yfrc/96d389JppSHp6vGK/CixEeSdrmLmdLYtTbH4mNqP53kp80fGPEd8FXZkFEpjtXtLQiQoP5ug5014FYFqpWqPzICAPhup4HWwSEKiNQ6UfWx9lbFSJYkbrP1JpLf9USNA0LyXN0b1IFNPr57Q25xPerJ04WUjWbfZ1+WZsS58CBjjggcdx4LDKv5/NaHq/wEDcxrt42tQlaCzZezneSZYJSS3cyB8o8C83XwWXo/l8fpbdvyB4O7DJEcL6vWS8jSyiIP8eKSRS81Dkv1UjZfjfomaF8Fh7bZYeatf4gSR3MH7aeaHy0LyVt6RX7Ly99WaVv0qWf3T6w"
|
||||
"scandit": "AZ70hgtZLmFWHbYP+BDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YfzKaR2xbfjsImjXJN7C/TE1CYXsv3DeqIzgDRA/kII4LzqoICWm9mnwejER1kMu1Vf+1NWbwUuYJjsQVQXYkwkWgnv53obevBZtjpgZqIzlStufIU+sPNEWSd9BlrLmiSEu6nXC5lbstyPJVaqihsFoBPNJ0Q+IgJUjqaxhTf6hGtNB3Rqcpv0ZT349NdK9mQ+9lAQYCwXdmYbELdlbZVSja0aJQlkf0TaAjixDbNcR32/VMIw98F2YxVRVWPnADUaJ9Bn8oa7NkOJIUfB7VAg1KtUl8IIwSXvRk436UtPZGxg+PQM7UXX/TgiBuqCQWdUChoH/QAoY2fyKRKgXJHnGdt+pBRQ2OYs7TZWCJLZsLKgnHV+eWh3Y3EB1hN9cmcszdnmYiyD1gCY8pSETFbWV01nVPvIuUTc+jMipv3NN81VQDS5/eU1VJNpRuDiufdBKJv0jjHQk+hTdqe+2GSmMD24ZG8FQXJZZPBCodWR1A81T8toCaIAGHnOfZeO7nxZu9Uo+6ohrVxc5F4szSizra+M3zfuFnm5FGgxCKt5uibLYgRyNcmR8/9vqTfMZgalTklbKHEFw1i+xOwrFrqRMh7FoovDRoI3QuaHLpV+ZUpZo3zTOQofdXPthKAmSLc11cjn509oTnnXUBBoBn/hErrwC/v8dZep1YEKM3wjfuIFsHRrsECswqNjwN/yOZCirm2VvFJEPMuKIwy+8jdNGncm8v4R9Br3c+wYJ8696L7Dg0iFShoyoP4OqIvBNY+dYyy935yGkIF2KI6l01xQZcWoHSVKPd6/78Iwy4lTKhtOqtu7ETJqOE53gQpR9jaAY0RiBB1SLm+Jbwt3ipSJiCDgKmkVmk5AU9HC0XYR/erjg13HF4hIcpLPW1ZWMKSxTqZ8z8FMJilInBgfcBwvjNE5seWvdFKltvlItnGhSh7BLUZ5UInDhl00NJBE2PdstDvRvQjLKvYUoFly3jONVsUfuQpzrcjT0g6gEgL8ZtlmaF11owcCvqhNDxWuTAJTX/xXf6WehxEB0qy3xCdxahbuneS3DPI0z2kAQwrx19i5r+RKQ8bWDaQ/OGY47sLPJgDgijEz16CvAMBSN0PvOso6FstsT/ynR3LLTPcY0QDw21Dv3wNHNa9HbanJcb3/MuhZGlrKp7"
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
},
|
||||
"paymentStatus": {
|
||||
"0": "-",
|
||||
"1": "ProformaInvoicePrinted",
|
||||
"2": "InvoicePrinted",
|
||||
"4": "Bezahlt",
|
||||
"8": "OnApproval",
|
||||
"16": "Kostenlos",
|
||||
"32": "Mahnung",
|
||||
"64": "ProformaInvoicePaid",
|
||||
"128": "Canceled",
|
||||
"256": "Mahnung",
|
||||
"512": "PartiallyPaid",
|
||||
"1024": "Outstanding"
|
||||
},
|
||||
"paymentType": {
|
||||
"0": "-",
|
||||
"1": "WhenCollecting",
|
||||
"2": "Kostenlos",
|
||||
"4": "Bar",
|
||||
"8": "DirectDebit",
|
||||
"16": "DebitAdviceMandate",
|
||||
"32": "DebitCard",
|
||||
"64": "Kreditkarte",
|
||||
"128": "Rechnung",
|
||||
"256": "Vorkasse",
|
||||
"512": "Voucher",
|
||||
"1024": "CollectiveInvoice",
|
||||
"2048": "PayPal",
|
||||
"4096": "InstantTransfer",
|
||||
"8192": "BonusCard",
|
||||
"16384": "AmazonPay"
|
||||
},
|
||||
"receiptType": {
|
||||
"0": "-",
|
||||
"1": "Lieferschein",
|
||||
"2": "Gutschrift",
|
||||
"4": "Sammelgutschrift",
|
||||
"8": "CollectiveCreditNote",
|
||||
"16": "Sammellieferschein für Kundenkartenkäufe",
|
||||
"32": "Sammelgutschrift für Kundenkartenkäufe",
|
||||
"64": "Zahlungsbeleg",
|
||||
"128": "Rechnung",
|
||||
"256": "Sammelrechnung",
|
||||
"512": "Proformarechnung / Vorauskasse",
|
||||
"1024": "Bon/Quittung",
|
||||
"2048": "Rücknahmebeleg"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -3,8 +3,7 @@
|
||||
"silentRefresh": {
|
||||
"interval": 300000
|
||||
},
|
||||
"debug": false,
|
||||
|
||||
"debug": true,
|
||||
"@cdn/product-image": {
|
||||
"url": "https://produktbilder.paragon-data.net"
|
||||
},
|
||||
@@ -75,13 +74,60 @@
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "Ae8F2Wx2RMq5Lvn7UUAlWzVFZTt2+ubMAF8XtDpmPlNkBeG/LWs1M7AbgDW0LQqYLnszClEENaEHS56/6Ts2vrJ1Ux03CXUjK3jUvZpF5OchXR1CpnmpepJ6WxPCd7LMVHUGG1BbwPLDTFjP3y8uT0caTSmmGrYQWAs4CZcEF+ZBabP0z7vfm+hCZF/ebj9qqCJZcW8nH/n19hohshllzYBjFXjh87P2lIh1s6yZS3OaQWWXo/o0AKdxx7T6CVyR0/G5zq6uYJWf6rs3euUBEhpzOZHbHZK86Lvy2AVBEyVkkcttlDW1J2fA4l1W1JV/Xibz8AQV6kG482EpGF42KEoK48paZgX3e1AQsqUtmqzw294dcP4zMVstnw5/WrwKKi/5E/nOOJT2txYP1ZufIjPrwNFsqTlv7xCQlHjMzFGYwT816yD5qLRLbwOtjrkUPXNZLZ06T4upvWwJDmm8XgdeoDqMjHdcO4lwji1bl9EiIYJ/2qnsk9yZ2FqSaHzn4cbiL0f5u2HFlNAP0GUujGRlthGhHi6o4dFU+WAxKsFMKVt+SfoQUazNKHFVQgiAklTIZxIc/HUVzRvOLMxf+wFDerraBtcqGJg+g/5mrWYqeDBGhCBHtKiYf6244IJ4afzNTiH1/30SJcRzXwbEa3A7q1fJTx9/nLTOfVPrJKBQs7f/OQs2dA7LDCel8mzXdbjvsNQaeU5+iCIAq6zbTNKy1xT8wwj+VZrQmtNJs+qeznD+u29nCM24h8xCmRpvNPo4/Mww/lrTNrrNwLBSn1pMIwsH7yS9hH0v0oNAM3A6bVtk1D9qEkbyw+xZa+MZGpMP0D0CdcsqHalPcm5r/Ik="
|
||||
"scandit": "Ac2kvx5ZOzjvFl/LuAd6wds3C30YJ4g8Cm6PX4sgUnKPePVMuH+rFQIyVNn1YdS3myORojEOBsIZWhMw2nRUGBtOnQ5FO+cRHgQu0pkP+VG6OYvt8ETUTn8Aa2f9bmfqclO3LI8WN8psWr+adkZEtqNTvCgyDLZaICh8S7RfmwJVVWaOPX4LDagGhLDPS2YQdg+ibpR0l0ZlX2h/3GttofE64HOlBN3QtDB8yihHJNgVcUVy2UQVS+BXOyvIfZEFbFgPYVt5HZ0aQgcISlYVAmJvRsHyeKYRUnIi3ZN73EQmHzWcOV4/HWVoTs1MTW0mxV074vNwqExYW9LYmz9zgLUD7FMnKMFClkzRBHRN1CC7brosCnFkZWQp3CV4Ua48Fn9GW0Zpn/4MIZgzSU26inl5ZnT3dCc2+3BH3Us1uugTUrOPwFuwsPpr4NZYXWJMOmcm4kBBVJd0Uwk28GyZM7x1hXADcQgcc23+gDtbbUZWVmr3TE7GBcV3j+XUeOk8nHZw3DsYJ46MT2sSfks3QXRl4tBkBad6M+UxW4tb2IQC/4K9IXKhDN8VYXpzrrRHJNvOiH5+NrixthDZHHd/MGNuBDrJFOuXq8L7O6PxBoVZ0NPXmCO5vKyYdhBz5gJ5u3vNkSke7p+cDcvFicsVyNWRaaoFL0UN9gxFVMY8hkJKBZyGxZL2LEDXD44PxPsDnygpDC1Jyc7pkhEA0fKSc9aXZb1HDpwe1hqyyRVBtHkgPiN78GmJImbaUlj8XsK3yVyAjs2XvPR0/3ASHS53ViwzWKL3Oi8I515IJDtDhlvrkeh7MrWMaEu9k6ZQXJi1uJsh3JGfyS+yDlPjePVdsVqnZ4uw9pKMXvjlJeNcIiGM2Cf5S89nk2Qe/56MrKB9Frm6Q5wQHai8TNdCZYBi67dmAX8KHPXvEU4K6KyyW89YGcabZQ3eOJDr4oqW9ZcYPBttREdH3WI/HxvpEq6bqoDhT9AxpIWEMVb6y/DcDHSEresepibug4qOr9xOPq0yk2uiWYhPubFnCk7thQCXOGv9crWnQoOrt9c1qoaWXM4YmKqfcaQ67Tn+uFQmYTZyqw4jlJU4GgKe5/GNCVQM5aNUg1J0Px1NlFCS+rrIDyMQp0byFcgTd/E9sA5d1+YZKHKmJiQwEAz6oU9yyoUlxntSI42GHB/UttPc7Hj14V5+oJ+Yz+CZodmkXFg57Vx4NuxveNtO"
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
},
|
||||
"paymentStatus": {
|
||||
"0": "-",
|
||||
"1": "ProformaInvoicePrinted",
|
||||
"2": "InvoicePrinted",
|
||||
"4": "Bezahlt",
|
||||
"8": "OnApproval",
|
||||
"16": "Kostenlos",
|
||||
"32": "Mahnung",
|
||||
"64": "ProformaInvoicePaid",
|
||||
"128": "Canceled",
|
||||
"256": "Mahnung",
|
||||
"512": "PartiallyPaid",
|
||||
"1024": "Outstanding"
|
||||
},
|
||||
"paymentType": {
|
||||
"0": "-",
|
||||
"1": "WhenCollecting",
|
||||
"2": "Kostenlos",
|
||||
"4": "Bar",
|
||||
"8": "DirectDebit",
|
||||
"16": "DebitAdviceMandate",
|
||||
"32": "DebitCard",
|
||||
"64": "Kreditkarte",
|
||||
"128": "Rechnung",
|
||||
"256": "Vorkasse",
|
||||
"512": "Voucher",
|
||||
"1024": "CollectiveInvoice",
|
||||
"2048": "PayPal",
|
||||
"4096": "InstantTransfer",
|
||||
"8192": "BonusCard",
|
||||
"16384": "AmazonPay"
|
||||
},
|
||||
"receiptType": {
|
||||
"0": "-",
|
||||
"1": "Lieferschein",
|
||||
"2": "Gutschrift",
|
||||
"4": "Sammelgutschrift",
|
||||
"8": "CollectiveCreditNote",
|
||||
"16": "Sammellieferschein für Kundenkartenkäufe",
|
||||
"32": "Sammelgutschrift für Kundenkartenkäufe",
|
||||
"64": "Zahlungsbeleg",
|
||||
"128": "Rechnung",
|
||||
"256": "Sammelrechnung",
|
||||
"512": "Proformarechnung / Vorauskasse",
|
||||
"1024": "Bon/Quittung",
|
||||
"2048": "Rücknahmebeleg"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { BranchDTO } from '@generated/swagger/checkout-api';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { isBoolean, isNumber } from '@utils/common';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { first, map, switchMap } from 'rxjs/operators';
|
||||
@@ -35,9 +35,7 @@ export class ApplicationService {
|
||||
|
||||
getProcesses$(section?: 'customer' | 'branch') {
|
||||
const processes$ = this.store.select(selectProcesses);
|
||||
return processes$.pipe(
|
||||
map((processes) => processes.filter((process) => (section ? process.section === section : true))),
|
||||
);
|
||||
return processes$.pipe(map((processes) => processes.filter((process) => (section ? process.section === section : true))));
|
||||
}
|
||||
|
||||
getProcessById$(processId: number): Observable<ApplicationProcess> {
|
||||
@@ -137,10 +135,7 @@ export class ApplicationService {
|
||||
this.store.dispatch(setSection({ section }));
|
||||
}
|
||||
|
||||
getLastActivatedProcessWithSectionAndType$(
|
||||
section: 'customer' | 'branch',
|
||||
type: string,
|
||||
): Observable<ApplicationProcess> {
|
||||
getLastActivatedProcessWithSectionAndType$(section: 'customer' | 'branch', type: string): Observable<ApplicationProcess> {
|
||||
return this.getProcesses$(section).pipe(
|
||||
map((processes) =>
|
||||
processes
|
||||
|
||||
@@ -11,17 +11,8 @@ export const addProcess = createAction(`${prefix} Add Process`, props<{ process:
|
||||
|
||||
export const removeProcess = createAction(`${prefix} Remove Process`, props<{ processId: number }>());
|
||||
|
||||
export const setActivatedProcess = createAction(
|
||||
`${prefix} Set Activated Process`,
|
||||
props<{ activatedProcessId: number }>(),
|
||||
);
|
||||
export const setActivatedProcess = createAction(`${prefix} Set Activated Process`, props<{ activatedProcessId: number }>());
|
||||
|
||||
export const patchProcess = createAction(
|
||||
`${prefix} Patch Process`,
|
||||
props<{ processId: number; changes: Partial<ApplicationProcess> }>(),
|
||||
);
|
||||
export const patchProcess = createAction(`${prefix} Patch Process`, props<{ processId: number; changes: Partial<ApplicationProcess> }>());
|
||||
|
||||
export const patchProcessData = createAction(
|
||||
`${prefix} Patch Process Data`,
|
||||
props<{ processId: number; data: Record<string, any> }>(),
|
||||
);
|
||||
export const patchProcessData = createAction(`${prefix} Patch Process Data`, props<{ processId: number; data: Record<string, any> }>());
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
import { coerceArray } from "@angular/cdk/coercion";
|
||||
import { inject, Injectable } from "@angular/core";
|
||||
import { Config } from "@core/config";
|
||||
import { isNullOrUndefined } from "@utils/common";
|
||||
import { AuthConfig, OAuthService } from "angular-oauth2-oidc";
|
||||
import { JwksValidationHandler } from "angular-oauth2-oidc-jwks";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
/**
|
||||
* Storage key for the URL to redirect to after login
|
||||
*/
|
||||
const REDIRECT_URL_KEY = "auth_redirect_url";
|
||||
import { coerceArray, coerceStringArray } from '@angular/cdk/coercion';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Config } from '@core/config';
|
||||
import { isNullOrUndefined } from '@utils/common';
|
||||
import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
|
||||
import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
|
||||
import { asapScheduler, BehaviorSubject } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root",
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthService {
|
||||
private readonly _initialized = new BehaviorSubject<boolean>(false);
|
||||
@@ -21,71 +16,49 @@ export class AuthService {
|
||||
}
|
||||
|
||||
private _authConfig: AuthConfig;
|
||||
|
||||
constructor(
|
||||
private _config: Config,
|
||||
private readonly _oAuthService: OAuthService,
|
||||
) {
|
||||
this._oAuthService.events?.subscribe((event) => {
|
||||
if (event.type === "token_received") {
|
||||
console.log(
|
||||
"SSO Token Expiration:",
|
||||
new Date(this._oAuthService.getAccessTokenExpiration()),
|
||||
);
|
||||
|
||||
// Handle redirect after successful authentication
|
||||
setTimeout(() => {
|
||||
const redirectUrl = this._getAndClearRedirectUrl();
|
||||
if (redirectUrl) {
|
||||
window.location.href = redirectUrl;
|
||||
}
|
||||
}, 100);
|
||||
if (event.type === 'token_received') {
|
||||
console.log('SSO Token Expiration:', new Date(this._oAuthService.getAccessTokenExpiration()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async init() {
|
||||
if (this._initialized.getValue()) {
|
||||
throw new Error("AuthService is already initialized");
|
||||
throw new Error('AuthService is already initialized');
|
||||
}
|
||||
|
||||
this._authConfig = this._config.get("@core/auth");
|
||||
this._authConfig = this._config.get('@core/auth');
|
||||
|
||||
this._authConfig.redirectUri = window.location.origin;
|
||||
|
||||
this._authConfig.silentRefreshRedirectUri =
|
||||
window.location.origin + "/silent-refresh.html";
|
||||
this._authConfig.silentRefreshRedirectUri = window.location.origin + '/silent-refresh.html';
|
||||
this._authConfig.useSilentRefresh = true;
|
||||
|
||||
this._oAuthService.configure(this._authConfig);
|
||||
this._oAuthService.tokenValidationHandler = new JwksValidationHandler();
|
||||
|
||||
this._oAuthService.setupAutomaticSilentRefresh();
|
||||
try {
|
||||
await this._oAuthService.loadDiscoveryDocumentAndTryLogin();
|
||||
} catch (error) {
|
||||
this.login();
|
||||
|
||||
await this._oAuthService.loadDiscoveryDocumentAndTryLogin();
|
||||
throw error;
|
||||
}
|
||||
|
||||
this._initialized.next(true);
|
||||
}
|
||||
|
||||
isAuthenticated() {
|
||||
return this.isIdTokenValid();
|
||||
}
|
||||
|
||||
isIdTokenValid() {
|
||||
console.log(
|
||||
"ID Token Expiration:",
|
||||
new Date(this._oAuthService.getIdTokenExpiration()),
|
||||
);
|
||||
return this._oAuthService.hasValidIdToken();
|
||||
}
|
||||
|
||||
isAccessTokenValid() {
|
||||
console.log(
|
||||
"ACCESS Token Expiration:",
|
||||
new Date(this._oAuthService.getAccessTokenExpiration()),
|
||||
);
|
||||
return this._oAuthService.hasValidAccessToken();
|
||||
}
|
||||
|
||||
getToken() {
|
||||
return this._oAuthService.getAccessToken();
|
||||
}
|
||||
@@ -107,31 +80,14 @@ export class AuthService {
|
||||
if (isNullOrUndefined(token)) {
|
||||
return null;
|
||||
}
|
||||
const base64Url = token.split(".")[1];
|
||||
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
||||
const base64Url = token.split('.')[1];
|
||||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||||
|
||||
const encoded = window.atob(base64);
|
||||
return JSON.parse(encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the URL to redirect to after successful login
|
||||
*/
|
||||
_saveRedirectUrl(): void {
|
||||
localStorage.setItem(REDIRECT_URL_KEY, window.location.href);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets and clears the saved redirect URL
|
||||
*/
|
||||
_getAndClearRedirectUrl(): string | null {
|
||||
const url = localStorage.getItem(REDIRECT_URL_KEY);
|
||||
localStorage.removeItem(REDIRECT_URL_KEY);
|
||||
return url;
|
||||
}
|
||||
|
||||
login() {
|
||||
this._saveRedirectUrl();
|
||||
this._oAuthService.initLoginFlow();
|
||||
}
|
||||
|
||||
@@ -143,12 +99,15 @@ export class AuthService {
|
||||
|
||||
async logout() {
|
||||
await this._oAuthService.revokeTokenAndLogout();
|
||||
// asapScheduler.schedule(() => {
|
||||
// window.location.reload();
|
||||
// }, 250);
|
||||
}
|
||||
|
||||
hasRole(role: string | string[]) {
|
||||
const roles = coerceArray(role);
|
||||
|
||||
const userRoles = this.getClaimByKey("role");
|
||||
const userRoles = this.getClaimByKey('role');
|
||||
|
||||
if (isNullOrUndefined(userRoles)) {
|
||||
return false;
|
||||
@@ -159,10 +118,7 @@ export class AuthService {
|
||||
|
||||
async refresh() {
|
||||
try {
|
||||
if (
|
||||
this._authConfig.responseType.includes("code") &&
|
||||
this._authConfig.scope.includes("offline_access")
|
||||
) {
|
||||
if (this._authConfig.responseType.includes('code') && this._authConfig.scope.includes('offline_access')) {
|
||||
await this._oAuthService.refreshToken();
|
||||
} else {
|
||||
await this._oAuthService.silentRefresh();
|
||||
|
||||
@@ -3,7 +3,6 @@ import { AuthService } from './auth.service';
|
||||
|
||||
@Directive({
|
||||
selector: '[ifRole],[ifRoleElse],[ifNotRole],[ifNotRoleElse]',
|
||||
standalone: false,
|
||||
})
|
||||
export class IfRoleDirective implements OnChanges {
|
||||
@Input()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from './auth.module';
|
||||
export * from './auth.service';
|
||||
export * from './if-role.directive';
|
||||
export * from './login.strategy';
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import { ScanAdapterService } from '@adapter/scan';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { toSignal } from '@angular/core/rxjs-interop';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { UiConfirmModalComponent, UiModalResult, UiModalService } from '@ui/modal';
|
||||
import { injectNetworkStatus$ } from '../../app/services';
|
||||
import { AuthService } from './auth.service';
|
||||
import { AuthService as IsaAuthService } from '@generated/swagger/isa-api';
|
||||
import { firstValueFrom, lastValueFrom } from 'rxjs';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class LoginStrategy {
|
||||
private readonly environmentService = inject(EnvironmentService);
|
||||
private readonly networkStatus = toSignal(injectNetworkStatus$());
|
||||
private readonly modal = inject(UiModalService);
|
||||
private readonly scanAdapterService = inject(ScanAdapterService);
|
||||
private readonly isaAuthService = inject(IsaAuthService);
|
||||
private readonly authService = inject(AuthService);
|
||||
|
||||
async login(title = 'Anmeldung') {
|
||||
console.log('LoginStrategy.login');
|
||||
|
||||
let loginModalResult: UiModalResult<boolean>;
|
||||
|
||||
if (this.authService.isIdTokenValid()) {
|
||||
console.log('LoginStrategy.login: idToken is valid');
|
||||
await this.authService.login();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (this.environmentService.isMobileDevice()) {
|
||||
console.log('LoginStrategy.login: isMobileDevice');
|
||||
do {
|
||||
const loginModal = this.modal.open({
|
||||
content: UiConfirmModalComponent,
|
||||
title,
|
||||
config: {
|
||||
canClose: false,
|
||||
backdropClose: false,
|
||||
},
|
||||
data: {
|
||||
message: 'Bitte wählen Sie die Anmeldeoption aus.',
|
||||
rejectLabel: 'Anmeldung mit Logindaten',
|
||||
confirmLabel: 'Anmeldung mit Keycard',
|
||||
},
|
||||
});
|
||||
|
||||
loginModalResult = await loginModal.afterClosed$.toPromise();
|
||||
} while (this.networkStatus() === 'offline');
|
||||
}
|
||||
} catch (error) {}
|
||||
|
||||
try {
|
||||
if (loginModalResult.data) {
|
||||
const result = await lastValueFrom(this.scanAdapterService.scan());
|
||||
|
||||
if (typeof result === 'string') {
|
||||
const res = await firstValueFrom(
|
||||
this.isaAuthService.AuthLogin({
|
||||
code: result,
|
||||
application: 'isa',
|
||||
hostname: location.host,
|
||||
}),
|
||||
);
|
||||
|
||||
if (res.token) {
|
||||
console.log('LoginStrategy.login: setKeyCardToken', res.token);
|
||||
this.authService.setKeyCardToken(res.token);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {}
|
||||
|
||||
console.log('LoginStrategy.login: login');
|
||||
await this.authService.login();
|
||||
}
|
||||
}
|
||||
@@ -120,10 +120,7 @@ export class BreadcrumbService {
|
||||
|
||||
if (recursive) {
|
||||
const breadcrumbs = await this.getBreadcrumbByKey$(breadcrumb.key).pipe(take(1)).toPromise();
|
||||
breadcrumbsToRemove = [
|
||||
...breadcrumbsToRemove,
|
||||
...breadcrumbs.filter((crumb) => crumb.timestamp > breadcrumb.timestamp),
|
||||
];
|
||||
breadcrumbsToRemove = [...breadcrumbsToRemove, ...breadcrumbs.filter((crumb) => crumb.timestamp > breadcrumb.timestamp)];
|
||||
}
|
||||
|
||||
if (!breadcrumbsToRemove.length) {
|
||||
@@ -138,10 +135,7 @@ export class BreadcrumbService {
|
||||
crumbs.forEach((crumb) => this.removeBreadcrumb(crumb.id));
|
||||
}
|
||||
|
||||
getLatestBreadcrumbForSection(
|
||||
section: 'customer' | 'branch',
|
||||
predicate: (crumb: Breadcrumb) => boolean = (_) => true,
|
||||
) {
|
||||
getLatestBreadcrumbForSection(section: 'customer' | 'branch', predicate: (crumb: Breadcrumb) => boolean = (_) => true) {
|
||||
return this.store
|
||||
.select(selectors.selectBreadcrumbsBySection, { section })
|
||||
.pipe(map((crumbs) => crumbs.sort((a, b) => b.timestamp - a.timestamp).find((f) => predicate(f))));
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface Breadcrumb {
|
||||
/**
|
||||
* Query Parameter
|
||||
*/
|
||||
params?: object;
|
||||
params?: Object;
|
||||
|
||||
/**
|
||||
* Timestamp
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
describe('Breadcrumb Actions', () => {});
|
||||
|
||||
@@ -11,10 +11,7 @@ export const addBreadcrumb = createAction(`${prefix} Add Breadcrumb`, props<{ br
|
||||
/**
|
||||
* Action um Breadcrumb im State zu ändern
|
||||
*/
|
||||
export const updateBreadcrumb = createAction(
|
||||
`${prefix} Update Breadcrumb`,
|
||||
props<{ id: number; changes: Partial<Breadcrumb> }>(),
|
||||
);
|
||||
export const updateBreadcrumb = createAction(`${prefix} Update Breadcrumb`, props<{ id: number; changes: Partial<Breadcrumb> }>());
|
||||
|
||||
/**
|
||||
* Action um Breadcrumb im State zu entfernen
|
||||
|
||||
@@ -43,10 +43,7 @@ describe('Breadcrumb Reducer', () => {
|
||||
|
||||
const state = breadcrumbReducer(INIT, action.addBreadcrumb({ breadcrumb }));
|
||||
|
||||
const fixture = breadcrumbReducer(
|
||||
state,
|
||||
action.updateBreadcrumb({ id: breadcrumb.id, changes: { name: 'Test Name 2' } }),
|
||||
);
|
||||
const fixture = breadcrumbReducer(state, action.updateBreadcrumb({ id: breadcrumb.id, changes: { name: 'Test Name 2' } }));
|
||||
|
||||
expect(fixture.entities[breadcrumb.id]).toEqual(expected);
|
||||
});
|
||||
|
||||
@@ -10,46 +10,26 @@ describe('Breadcrumb Selectors', () => {
|
||||
beforeEach(() => {
|
||||
state = breadcrumbReducer(
|
||||
INIT,
|
||||
action.addBreadcrumb({
|
||||
breadcrumb: { id: 1, key: 'unit-test-1', path: '', name: 'Unit Test 1', section: 'customer' },
|
||||
}),
|
||||
action.addBreadcrumb({ breadcrumb: { id: 1, key: 'unit-test-1', path: '', name: 'Unit Test 1', section: 'customer' } }),
|
||||
);
|
||||
state = breadcrumbReducer(
|
||||
state,
|
||||
action.addBreadcrumb({
|
||||
breadcrumb: {
|
||||
id: 2,
|
||||
key: 'unit-test-1',
|
||||
path: '',
|
||||
name: 'Unit Test 1',
|
||||
tags: ['details'],
|
||||
section: 'customer',
|
||||
},
|
||||
breadcrumb: { id: 2, key: 'unit-test-1', path: '', name: 'Unit Test 1', tags: ['details'], section: 'customer' },
|
||||
}),
|
||||
);
|
||||
state = breadcrumbReducer(
|
||||
state,
|
||||
action.addBreadcrumb({
|
||||
breadcrumb: { id: 3, key: 'unit-test-2', path: '', name: 'Unit Test 1', section: 'customer' },
|
||||
}),
|
||||
action.addBreadcrumb({ breadcrumb: { id: 3, key: 'unit-test-2', path: '', name: 'Unit Test 1', section: 'customer' } }),
|
||||
);
|
||||
state = breadcrumbReducer(
|
||||
state,
|
||||
action.addBreadcrumb({ breadcrumb: { id: 4, key: 'unit-test-3', path: '', name: 'Unit Test 1', section: 'customer' } }),
|
||||
);
|
||||
state = breadcrumbReducer(
|
||||
state,
|
||||
action.addBreadcrumb({
|
||||
breadcrumb: { id: 4, key: 'unit-test-3', path: '', name: 'Unit Test 1', section: 'customer' },
|
||||
}),
|
||||
);
|
||||
state = breadcrumbReducer(
|
||||
state,
|
||||
action.addBreadcrumb({
|
||||
breadcrumb: {
|
||||
id: 5,
|
||||
key: 'unit-test-3',
|
||||
path: '',
|
||||
name: 'Unit Test 1',
|
||||
tags: ['details'],
|
||||
section: 'customer',
|
||||
},
|
||||
breadcrumb: { id: 5, key: 'unit-test-3', path: '', name: 'Unit Test 1', tags: ['details'], section: 'customer' },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -20,9 +20,7 @@ export const selectBreadcrumbById = createSelector(selectEntities, (entities, id
|
||||
/**
|
||||
* Gibt alle Breadcrumb Entities als Array zurück die den key enthalten
|
||||
*/
|
||||
export const selectBreadcrumbsByKey = createSelector(selectAll, (entities, key: string) =>
|
||||
entities.filter((crumb) => crumb.key == key),
|
||||
);
|
||||
export const selectBreadcrumbsByKey = createSelector(selectAll, (entities, key: string) => entities.filter((crumb) => crumb.key == key));
|
||||
|
||||
/**
|
||||
* Gibt alle Breadcrumb Entities als Array zurück die den key und tag enthalten
|
||||
@@ -39,15 +37,12 @@ export const selectBreadcrumbsByKeyAndTag = createSelector(
|
||||
export const selectBreadcrumbsByKeyAndTags = createSelector(
|
||||
selectAll,
|
||||
(entities: Breadcrumb[], { key, tags }: { key: string; tags: string[] }) =>
|
||||
entities.filter(
|
||||
(crumb) => crumb.key == key && isArray(crumb.tags) && tags.every((tag) => crumb.tags.includes(tag)),
|
||||
),
|
||||
entities.filter((crumb) => crumb.key == key && isArray(crumb.tags) && tags.every((tag) => crumb.tags.includes(tag))),
|
||||
);
|
||||
|
||||
/**
|
||||
* Gibt alle Breadcrumb Entities als Array zurück die die tags enthalten
|
||||
*/
|
||||
export const selectBreadcrumbsBySection = createSelector(
|
||||
selectAll,
|
||||
(entities: Breadcrumb[], { section }: { section: string }) => entities.filter((crumb) => crumb.section === section),
|
||||
export const selectBreadcrumbsBySection = createSelector(selectAll, (entities: Breadcrumb[], { section }: { section: string }) =>
|
||||
entities.filter((crumb) => crumb.section === section),
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createEntityAdapter, EntityState } from '@ngrx/entity';
|
||||
import { Breadcrumb } from '../defs';
|
||||
|
||||
export type BreadcrumbState = EntityState<Breadcrumb>
|
||||
export interface BreadcrumbState extends EntityState<Breadcrumb> {}
|
||||
|
||||
export const featureName = 'core-breadcrumb';
|
||||
|
||||
|
||||
8
apps/isa-app/src/core/cache/cache.service.ts
vendored
8
apps/isa-app/src/core/cache/cache.service.ts
vendored
@@ -34,7 +34,7 @@ export class CacheService {
|
||||
return 'cache';
|
||||
}
|
||||
|
||||
private getKey(token: object | string): string {
|
||||
private getKey(token: Object | string): string {
|
||||
if (typeof token === 'string') {
|
||||
return this.hash(token);
|
||||
}
|
||||
@@ -105,7 +105,7 @@ export class CacheService {
|
||||
});
|
||||
}
|
||||
|
||||
private async cached(token: object | string): Promise<DbEntry<any> | undefined> {
|
||||
private async cached(token: Object | string): Promise<DbEntry<any> | undefined> {
|
||||
const store = await this.getObjectStore();
|
||||
return new Promise<DbEntry<any> | undefined>((resolve, reject) => {
|
||||
const request = store.get(this.getKey(token));
|
||||
@@ -118,7 +118,7 @@ export class CacheService {
|
||||
});
|
||||
}
|
||||
|
||||
async get<T = any>(token: object | string): Promise<T | undefined> {
|
||||
async get<T = any>(token: Object | string): Promise<T | undefined> {
|
||||
const cached = await this.cached(token);
|
||||
|
||||
if (!cached) {
|
||||
@@ -133,7 +133,7 @@ export class CacheService {
|
||||
return cached.data;
|
||||
}
|
||||
|
||||
async delete(token: object | string): Promise<void> {
|
||||
async delete(token: Object | string): Promise<void> {
|
||||
const store = await this.getObjectStore('readwrite');
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const request = store.delete(this.getKey(token));
|
||||
|
||||
@@ -4,10 +4,7 @@ import { CommandService } from './command.service';
|
||||
import { FEATURE_ACTION_HANDLERS, ROOT_ACTION_HANDLERS } from './tokens';
|
||||
|
||||
export function provideActionHandlers(actionHandlers: Type<ActionHandler>[]): Provider[] {
|
||||
return [
|
||||
CommandService,
|
||||
actionHandlers.map((handler) => ({ provide: FEATURE_ACTION_HANDLERS, useClass: handler, multi: true })),
|
||||
];
|
||||
return [CommandService, actionHandlers.map((handler) => ({ provide: FEATURE_ACTION_HANDLERS, useClass: handler, multi: true }))];
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
@@ -15,20 +12,14 @@ export class CoreCommandModule {
|
||||
static forRoot(actionHandlers: Type<ActionHandler>[]): ModuleWithProviders<CoreCommandModule> {
|
||||
return {
|
||||
ngModule: CoreCommandModule,
|
||||
providers: [
|
||||
CommandService,
|
||||
actionHandlers.map((handler) => ({ provide: ROOT_ACTION_HANDLERS, useClass: handler, multi: true })),
|
||||
],
|
||||
providers: [CommandService, actionHandlers.map((handler) => ({ provide: ROOT_ACTION_HANDLERS, useClass: handler, multi: true }))],
|
||||
};
|
||||
}
|
||||
|
||||
static forChild(actionHandlers: Type<ActionHandler>[]): ModuleWithProviders<CoreCommandModule> {
|
||||
return {
|
||||
ngModule: CoreCommandModule,
|
||||
providers: [
|
||||
CommandService,
|
||||
actionHandlers.map((handler) => ({ provide: FEATURE_ACTION_HANDLERS, useClass: handler, multi: true })),
|
||||
],
|
||||
providers: [CommandService, actionHandlers.map((handler) => ({ provide: FEATURE_ACTION_HANDLERS, useClass: handler, multi: true }))],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
/**
|
||||
* Config loader interface for loading configurations
|
||||
*/
|
||||
export interface ConfigLoader {
|
||||
load(): Promise<any>;
|
||||
}
|
||||
4
apps/isa-app/src/core/config/config-loaders/index.ts
Normal file
4
apps/isa-app/src/core/config/config-loaders/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// start:ng42.barrel
|
||||
export * from './config-loader';
|
||||
export * from './json.config-loader';
|
||||
// end:ng42.barrel
|
||||
@@ -0,0 +1,36 @@
|
||||
// unit test JsonConfigLoader
|
||||
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
||||
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
|
||||
import { CORE_JSON_CONFIG_LOADER_URL } from '../tokens';
|
||||
import { JsonConfigLoader } from './json.config-loader';
|
||||
|
||||
describe('JsonConfigLoader', () => {
|
||||
let spectator: SpectatorService<JsonConfigLoader>;
|
||||
const createService = createServiceFactory({
|
||||
imports: [HttpClientTestingModule],
|
||||
service: JsonConfigLoader,
|
||||
mocks: [],
|
||||
providers: [{ provide: CORE_JSON_CONFIG_LOADER_URL, useValue: '/assets/config.json' }],
|
||||
});
|
||||
let httpTestingController: HttpTestingController;
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createService();
|
||||
httpTestingController = spectator.inject(HttpTestingController);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.service).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('load', () => {
|
||||
it('should call the provided url', async () => {
|
||||
const reqPromise = spectator.service.load();
|
||||
const req = httpTestingController.expectOne('/assets/config.json');
|
||||
req.flush({ unit: 'test' });
|
||||
const result = await reqPromise;
|
||||
httpTestingController.verify();
|
||||
expect(result).toEqual({ unit: 'test' });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { ConfigLoader } from './config-loader';
|
||||
import { CORE_JSON_CONFIG_LOADER_URL } from '../tokens';
|
||||
|
||||
@Injectable()
|
||||
export class JsonConfigLoader implements ConfigLoader {
|
||||
constructor(
|
||||
@Inject(CORE_JSON_CONFIG_LOADER_URL) private url: string,
|
||||
private http: HttpClient,
|
||||
) {}
|
||||
|
||||
load(): Promise<any> {
|
||||
return this.http.get(this.url).toPromise();
|
||||
}
|
||||
}
|
||||
7
apps/isa-app/src/core/config/config-module-options.ts
Normal file
7
apps/isa-app/src/core/config/config-module-options.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Type } from '@angular/core';
|
||||
import { ConfigLoader } from './config-loaders';
|
||||
|
||||
export interface ConfigModuleOptions {
|
||||
useConfigLoader: Type<ConfigLoader>;
|
||||
jsonConfigLoaderUrl?: string;
|
||||
}
|
||||
28
apps/isa-app/src/core/config/config.module.ts
Normal file
28
apps/isa-app/src/core/config/config.module.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { CORE_CONFIG_LOADER } from '@core/config';
|
||||
import { Config } from './config';
|
||||
import { ConfigModuleOptions } from './config-module-options';
|
||||
import { CORE_JSON_CONFIG_LOADER_URL } from './tokens';
|
||||
|
||||
export function _initializeConfigFactory(config: Config) {
|
||||
return () => config.init();
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class ConfigModule {
|
||||
static forRoot(options: ConfigModuleOptions): ModuleWithProviders<ConfigModule> {
|
||||
const configLoaderProvider = {
|
||||
provide: CORE_CONFIG_LOADER,
|
||||
useClass: options.useConfigLoader,
|
||||
};
|
||||
|
||||
return {
|
||||
ngModule: ConfigModule,
|
||||
providers: [
|
||||
Config,
|
||||
configLoaderProvider,
|
||||
options.jsonConfigLoaderUrl ? { provide: CORE_JSON_CONFIG_LOADER_URL, useValue: options.jsonConfigLoaderUrl } : null,
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
45
apps/isa-app/src/core/config/config.spec.ts
Normal file
45
apps/isa-app/src/core/config/config.spec.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
|
||||
import { Config } from './config';
|
||||
import { ConfigLoader } from './config-loaders';
|
||||
import { CORE_CONFIG_LOADER } from './tokens';
|
||||
|
||||
class TestConfigLoader implements ConfigLoader {
|
||||
load() {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
}
|
||||
|
||||
// Unit test Config
|
||||
describe('Config', () => {
|
||||
let spectator: SpectatorService<Config>;
|
||||
const createService = createServiceFactory({
|
||||
service: Config,
|
||||
providers: [{ provide: CORE_CONFIG_LOADER, useClass: TestConfigLoader }],
|
||||
});
|
||||
let configLoader: ConfigLoader;
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createService();
|
||||
configLoader = spectator.inject(CORE_CONFIG_LOADER);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.service).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('init()', () => {
|
||||
it('should load config and assigns it to _config', async () => {
|
||||
const config = { unit: 'test' };
|
||||
spyOn(configLoader, 'load').and.returnValue(Promise.resolve(config));
|
||||
await spectator.service.init();
|
||||
expect(spectator.service['_config']).toEqual(config);
|
||||
});
|
||||
});
|
||||
|
||||
describe('get()', () => {
|
||||
it('should return config value', () => {
|
||||
spectator.service['_config'] = { test: 'test' };
|
||||
expect(spectator.service.get('test')).toEqual('test');
|
||||
});
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user