659 lines
19 KiB
TypeScript
659 lines
19 KiB
TypeScript
import {
|
|
AfterViewInit,
|
|
Component,
|
|
ElementRef,
|
|
OnDestroy,
|
|
OnInit,
|
|
ViewChild,
|
|
} from '@angular/core';
|
|
import { CommonModule, DatePipe } from '@angular/common';
|
|
import {
|
|
Recipe,
|
|
Recipe01,
|
|
RecipeOverview,
|
|
RecipesDashboard,
|
|
} from 'src/app/core/models/recipe.model';
|
|
import { RecipeService } from 'src/app/core/services/recipe.service';
|
|
import { environment } from 'src/environments/environment';
|
|
import { RecipeModalComponent } from 'src/app/shared/modal/recipe-details/recipe-modal.component';
|
|
import {
|
|
BehaviorSubject,
|
|
Observable,
|
|
Subscription,
|
|
finalize,
|
|
map,
|
|
tap,
|
|
} from 'rxjs';
|
|
import * as lodash from 'lodash';
|
|
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
|
import { NgSelectModule } from '@ng-select/ng-select';
|
|
import { FormsModule } from '@angular/forms';
|
|
import { MaterialService } from 'src/app/core/services/material.service';
|
|
import { UserService } from 'src/app/core/services/user.service';
|
|
import { UserPermissions } from 'src/app/core/auth/userPermissions';
|
|
import { ToppingService } from 'src/app/core/services/topping.service';
|
|
import { copy, transformToTSV } from 'src/app/shared/helpers/copy';
|
|
import { getCountryMapSwitcher } from 'src/app/shared/helpers/recipe';
|
|
import { AsyncStorage } from 'src/app/shared/helpers/asyncStorage';
|
|
import { NotFoundHandler } from 'src/app/shared/helpers/notFoundHandler';
|
|
|
|
@Component({
|
|
selector: 'app-recipes',
|
|
standalone: true,
|
|
imports: [
|
|
CommonModule,
|
|
RouterLink,
|
|
DatePipe,
|
|
RecipeModalComponent,
|
|
NgSelectModule,
|
|
FormsModule,
|
|
],
|
|
templateUrl: './recipes.component.html',
|
|
})
|
|
export class RecipesComponent implements OnInit, OnDestroy, AfterViewInit {
|
|
recipesDashboard$!: Observable<RecipesDashboard>;
|
|
recipeOverviewList!: RecipeOverview[];
|
|
selectMaterialFilter: number[] | null = null;
|
|
materialList: { id: number; name: string | number }[] | null = null;
|
|
|
|
materialDetail:
|
|
| {
|
|
materialId: number;
|
|
name: string;
|
|
type: string;
|
|
}[]
|
|
| null = null;
|
|
|
|
toppings: {
|
|
toppingGroup: {} | null;
|
|
toppingList: {} | null;
|
|
} | null = null;
|
|
|
|
tableHeads: string[] = [
|
|
'Product Code',
|
|
'Name',
|
|
'Other Name',
|
|
'Description',
|
|
'Other Description',
|
|
'Last Updated',
|
|
];
|
|
private offset = 0;
|
|
private take = 20;
|
|
|
|
// isLoaded: boolean = false;
|
|
isLoadMore: boolean = true;
|
|
isHasMore: boolean = true;
|
|
|
|
private searchStr = '';
|
|
private oldSearchStr = '';
|
|
|
|
savedTmpfiles: any[] = [];
|
|
saveTab: boolean = false;
|
|
showSaveNoti: boolean = false;
|
|
|
|
department: string = this.route.parent!.snapshot.params['department'];
|
|
copyList: any[] = [];
|
|
|
|
currentVersion: number | undefined = undefined;
|
|
|
|
notfoundHandler = new NotFoundHandler();
|
|
|
|
@ViewChild('table', { static: false }) set content(table: ElementRef) {
|
|
table.nativeElement.addEventListener(
|
|
'scroll',
|
|
async () => {
|
|
if (this.isHasMore === false) {
|
|
return;
|
|
}
|
|
|
|
const { scrollTop, scrollHeight, clientHeight } = table.nativeElement;
|
|
const isBottom = scrollTop + clientHeight >= scrollHeight - 10;
|
|
if (isBottom && !this.isLoadMore) {
|
|
this.isLoadMore = true;
|
|
(
|
|
await this._recipeService.getRecipeOverview({
|
|
offset: this.offset,
|
|
take: this.take,
|
|
search: this.oldSearchStr,
|
|
filename: this._recipeService.getCurrentFile(),
|
|
country: await this._recipeService.getCurrentCountry(
|
|
this.department
|
|
),
|
|
materialIds: this.selectMaterialFilter || [],
|
|
})
|
|
).subscribe(({ result, hasMore, totalCount }) => {
|
|
// console.log("result in scroll", result);
|
|
if (this.recipeOverviewList) {
|
|
this.recipeOverviewList = this.recipeOverviewList.concat(result);
|
|
} else {
|
|
this.recipeOverviewList = result;
|
|
}
|
|
this.offset += 10;
|
|
this.isHasMore = hasMore;
|
|
this.isLoadMore = false;
|
|
});
|
|
}
|
|
},
|
|
{ passive: true }
|
|
);
|
|
}
|
|
|
|
constructor(
|
|
private _recipeService: RecipeService,
|
|
private _materialService: MaterialService,
|
|
private _toppingService: ToppingService,
|
|
private route: ActivatedRoute,
|
|
private _userService: UserService,
|
|
private _router: Router
|
|
) {}
|
|
|
|
async ngOnInit(): Promise<void> {
|
|
console.log('Trigger onInit where department = ', this.department);
|
|
|
|
// check if department is legit
|
|
|
|
this.notfoundHandler.handleInvalidDepartment(
|
|
this.department!,
|
|
async () => {
|
|
await this._router.navigate(['departments']);
|
|
window.location.reload();
|
|
},
|
|
async () => {
|
|
console.log('error callback', this.department!);
|
|
// await AsyncStorage.setItem(
|
|
// 'currentRecipeCountry',
|
|
// getCountryMapSwitcher(this.department!)
|
|
// );
|
|
|
|
// // get default file that should be opened
|
|
}
|
|
);
|
|
|
|
this.recipesDashboard$ = this._recipeService
|
|
.getRecipesDashboard({
|
|
filename: this._recipeService.getCurrentFile(),
|
|
country: await this._recipeService.getCurrentCountry(this.department!),
|
|
})
|
|
.pipe(
|
|
finalize(async () => {
|
|
(
|
|
await this._recipeService.getRecipeOverview({
|
|
offset: this.offset,
|
|
take: this.take,
|
|
search: this.oldSearchStr,
|
|
filename: this._recipeService.getCurrentFile(),
|
|
country: await this._recipeService.getCurrentCountry(
|
|
this.department!
|
|
),
|
|
materialIds: this.selectMaterialFilter || [],
|
|
})
|
|
).subscribe(({ result, hasMore, totalCount }) => {
|
|
this.recipeOverviewList = result;
|
|
this.offset += 10;
|
|
this.isHasMore = hasMore;
|
|
this.isLoadMore = false;
|
|
});
|
|
})
|
|
);
|
|
|
|
// : Lag assigned
|
|
|
|
this.recipesDashboard$.subscribe(async (data) => {
|
|
this.currentVersion = data.configNumber;
|
|
console.log('current version', this.currentVersion);
|
|
console.log('data : ', data);
|
|
|
|
// set default country and filename if was "default"
|
|
let currentFile = this._recipeService.getCurrentFile();
|
|
if (currentFile == 'default') {
|
|
await AsyncStorage.setItem(
|
|
'currentRecipeCountry',
|
|
await this._recipeService.getCurrentCountry(this.department!)
|
|
);
|
|
await AsyncStorage.setItem('currentRecipeFile', data.filename);
|
|
}
|
|
});
|
|
|
|
console.log('ngAfterViewInit::department', this.department);
|
|
console.log('::CurrentFile', this._recipeService.getCurrentFile());
|
|
|
|
(
|
|
await this._materialService.getFullMaterialDetail(
|
|
this.department,
|
|
this._recipeService.getCurrentFile()
|
|
)
|
|
).subscribe((mat) => {
|
|
this.materialDetail = mat;
|
|
console.log(
|
|
this.materialDetail?.length,
|
|
'[0]=',
|
|
mat?.at(0),
|
|
'current country',
|
|
this._recipeService.getCurrentCountry(),
|
|
'currentFile',
|
|
this._recipeService.getCurrentFile()
|
|
);
|
|
|
|
// check material detail
|
|
console.log('first material', this.materialDetail![0]);
|
|
});
|
|
|
|
// end of FIXME
|
|
|
|
// this._recipeService
|
|
// .getSavedTmp(
|
|
// await this._recipeService.getCurrentCountry(this.department),
|
|
// this._recipeService.getCurrentFile()
|
|
// )
|
|
// .subscribe({
|
|
// next: (files: any) => {
|
|
// console.log('Obtain saves: ', typeof files, files);
|
|
// this.showSaveNoti = false;
|
|
// if (files != undefined && typeof files === 'object') {
|
|
// if (files.files != null) {
|
|
// console.log(
|
|
// 'Obtain saves object: ',
|
|
// files.files[0],
|
|
// typeof files
|
|
// );
|
|
// this.savedTmpfiles = files.files;
|
|
// } else {
|
|
// this.showSaveNoti = false;
|
|
// this.savedTmpfiles = [];
|
|
// console.log(this.showSaveNoti, this.savedTmpfiles);
|
|
// }
|
|
// // let svf = (document.getElementById('select_savefile_modal') as HTMLInputElement)!.checked;
|
|
// // console.log("isSavedModalOpened",svf)
|
|
// } else {
|
|
// this.showSaveNoti = false;
|
|
// this.savedTmpfiles = [];
|
|
// console.log(this.showSaveNoti, this.savedTmpfiles);
|
|
// }
|
|
// },
|
|
// });
|
|
|
|
(await this._materialService.getMaterialCodes())
|
|
.pipe(
|
|
map((mat) =>
|
|
mat.map((m) => ({
|
|
id: m.materialID,
|
|
name: m.PackageDescription || m.materialID,
|
|
}))
|
|
)
|
|
)
|
|
.subscribe((materials) => {
|
|
this.materialList = materials;
|
|
});
|
|
|
|
(
|
|
await this._toppingService.getToppings(
|
|
this.department,
|
|
this._recipeService.getCurrentFile()
|
|
)
|
|
).subscribe((tp) => {
|
|
this.toppings = {
|
|
toppingGroup: tp.ToppingGroup,
|
|
toppingList: tp.ToppingList,
|
|
};
|
|
// console.log(this.toppings);
|
|
});
|
|
|
|
this.initRecipeSelection();
|
|
}
|
|
|
|
ngAfterViewInit(): void {
|
|
console.log('After view on init trigger');
|
|
}
|
|
|
|
setSearch(event: Event) {
|
|
console.log((event.target as HTMLInputElement).value);
|
|
this.searchStr = (event.target as HTMLInputElement).value;
|
|
}
|
|
|
|
async search(event: Event) {
|
|
// country
|
|
let country = await this._recipeService
|
|
.getCurrentCountry(this.department)
|
|
.then((country) => country);
|
|
|
|
this.offset = 0;
|
|
this.isLoadMore = true;
|
|
this.oldSearchStr = this.searchStr;
|
|
(
|
|
await this._recipeService.getRecipeOverview({
|
|
offset: this.offset,
|
|
take: this.take,
|
|
search: this.oldSearchStr,
|
|
filename: this._recipeService.getCurrentFile(),
|
|
country: country,
|
|
materialIds: this.selectMaterialFilter || [],
|
|
})
|
|
).subscribe(({ result, hasMore, totalCount }) => {
|
|
this.recipeOverviewList = result;
|
|
this.offset += 10;
|
|
this.isHasMore = hasMore;
|
|
this.isLoadMore = false;
|
|
});
|
|
}
|
|
|
|
// Recipe Version selection
|
|
currentCountryFilter: BehaviorSubject<string> = new BehaviorSubject<string>(
|
|
''
|
|
);
|
|
currentFileFilter: BehaviorSubject<string> = new BehaviorSubject<string>('');
|
|
recipeCountryFiltered: string[] = [];
|
|
recipeFileCountries: string[] = [];
|
|
|
|
currentCountryFilterSubScription: Subscription | null = null;
|
|
currentFileFilterSubScription: Subscription | null = null;
|
|
|
|
selectedCountry: string | null = null;
|
|
isCountrySelected: boolean = false;
|
|
|
|
private countryInputEl?: ElementRef<HTMLInputElement>;
|
|
private fileInputEl?: ElementRef<HTMLInputElement>;
|
|
|
|
@ViewChild('countryInput', { static: false }) set countryInput(
|
|
countryInput: ElementRef<HTMLInputElement>
|
|
) {
|
|
this.countryInputEl = countryInput;
|
|
}
|
|
|
|
@ViewChild('fileInput', { static: false }) set fileInput(
|
|
fileInput: ElementRef<HTMLInputElement>
|
|
) {
|
|
this.fileInputEl = fileInput;
|
|
}
|
|
|
|
private firstTimeOpenModal = true;
|
|
|
|
initRecipeSelection() {
|
|
if (this._recipeService.getRecipeFileCountries().length == 0) {
|
|
this._recipeService.getRecipeCountries().subscribe((countries) => {
|
|
this.recipeCountryFiltered = countries;
|
|
});
|
|
}
|
|
}
|
|
|
|
setCountryFilter(event: Event) {
|
|
this.currentCountryFilter.next((event.target as HTMLInputElement).value);
|
|
}
|
|
|
|
setFileFilter(event: Event) {
|
|
this.currentFileFilter.next((event.target as HTMLInputElement).value);
|
|
}
|
|
|
|
getRecipeCountries() {
|
|
if (this.firstTimeOpenModal) {
|
|
this.countryInputEl!.nativeElement.blur();
|
|
this.firstTimeOpenModal = false;
|
|
}
|
|
this.currentCountryFilterSubScription = this.currentCountryFilter.subscribe(
|
|
(c) => {
|
|
const countries = this._recipeService.getRecipeFileCountries();
|
|
|
|
// do perms
|
|
let accessibleCountries = [];
|
|
|
|
for (let country of countries) {
|
|
if (this.grantAccessCountry(country)) {
|
|
accessibleCountries.push(country);
|
|
}
|
|
}
|
|
|
|
console.log('granted accessible countries', accessibleCountries);
|
|
|
|
if (accessibleCountries.length > 0) {
|
|
this.recipeCountryFiltered = lodash.filter(
|
|
accessibleCountries,
|
|
(country) => country.toLowerCase().includes(c.toLowerCase())
|
|
);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
// Grant access to view a country recipe
|
|
grantAccessCountry(countryName: string): boolean {
|
|
if (
|
|
countryName.toLowerCase().startsWith('tha') &&
|
|
this._userService
|
|
.getCurrentUser()!
|
|
.permissions.includes(UserPermissions.THAI_PERMISSION)
|
|
) {
|
|
return true;
|
|
} else if (
|
|
countryName.toLowerCase().startsWith('aus') &&
|
|
this._userService
|
|
.getCurrentUser()!
|
|
.permissions.includes(UserPermissions.AUS_PERMISSION)
|
|
) {
|
|
return true;
|
|
} else if (
|
|
countryName.toLowerCase().startsWith('malay') &&
|
|
this._userService
|
|
.getCurrentUser()!
|
|
.permissions.includes(UserPermissions.MALAY_PERMISSION)
|
|
) {
|
|
return true;
|
|
} else if (
|
|
countryName.toLowerCase().startsWith('alpha-3') &&
|
|
this._userService
|
|
.getCurrentUser()!
|
|
.permissions.includes(UserPermissions.ALPHA3_PERMISSION)
|
|
) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
getRecipeFiles() {
|
|
this.currentFileFilterSubScription = this.currentFileFilter.subscribe(
|
|
(c) => {
|
|
if (this.selectedCountry === null) {
|
|
return;
|
|
}
|
|
|
|
const fileNames = this._recipeService.getRecipeFileNames(
|
|
this.selectedCountry
|
|
);
|
|
if (fileNames && fileNames.length > 0) {
|
|
this.recipeFileCountries = lodash.filter(fileNames, (file) =>
|
|
file.toLowerCase().includes(c.toLowerCase())
|
|
);
|
|
} else {
|
|
this._recipeService
|
|
.getRecipeFiles(this.selectedCountry)
|
|
.subscribe((files) => {
|
|
this.recipeFileCountries = lodash.filter(files, (file) =>
|
|
file.toLowerCase().includes(c.toLowerCase())
|
|
);
|
|
});
|
|
}
|
|
console.log(this.recipeFileCountries);
|
|
}
|
|
);
|
|
}
|
|
|
|
async countrySelected(country: string) {
|
|
this.selectedCountry = country;
|
|
this.isCountrySelected = true;
|
|
// localStorage.setItem('currentRecipeCountry', country);
|
|
|
|
await AsyncStorage.setItem('currentRecipeCountry', country);
|
|
|
|
// force reload, will fix this later
|
|
void this._router.navigate([`/${getCountryMapSwitcher(country)}/recipes`]);
|
|
}
|
|
|
|
async loadRecipe(recipeFileName: string) {
|
|
// clear all recipes
|
|
this.offset = 0;
|
|
this.isHasMore = true;
|
|
this.isLoadMore = true;
|
|
this.oldSearchStr = '';
|
|
// localStorage.setItem('currentRecipeFile', recipeFileName);
|
|
|
|
await AsyncStorage.setItem('currentRecipeFile', recipeFileName);
|
|
|
|
console.log(
|
|
'loadRecipe',
|
|
recipeFileName,
|
|
'currentCountry',
|
|
this.department,
|
|
'selectedCountry',
|
|
this.selectedCountry
|
|
);
|
|
|
|
// clear all menus
|
|
this.recipeOverviewList = [];
|
|
|
|
// this.recipesDashboard$ = this._recipeService.getRecipesDashboard({
|
|
// filename: recipeFileName,
|
|
// country: this.selectedCountry!,
|
|
// });
|
|
|
|
// this.recipesDashboard$.subscribe((data) => {
|
|
// this.currentVersion = data.configNumber;
|
|
// console.log('current version', this.currentVersion);
|
|
// });
|
|
|
|
// this._recipeService
|
|
// .getRecipeOverview({
|
|
// offset: this.offset,
|
|
// take: this.take,
|
|
// search: this.oldSearchStr,
|
|
// filename: recipeFileName,
|
|
// country: this.selectedCountry!,
|
|
// materialIds: this.selectMaterialFilter || [],
|
|
// })
|
|
// .subscribe(({ result, hasMore, totalCount }) => {
|
|
// this.recipeOverviewList = result;
|
|
// this.offset += 10;
|
|
// this.isHasMore = hasMore;
|
|
// this.isLoadMore = false;
|
|
// });
|
|
|
|
window.location.reload();
|
|
}
|
|
|
|
// end of Recipe Version selection
|
|
|
|
openJsonTab() {
|
|
window.open(
|
|
environment.api +
|
|
`/recipes/${this._recipeService.getCurrentCountry(
|
|
this.department
|
|
)}/${this._recipeService.getCurrentFile()}/json`,
|
|
'_blank'
|
|
);
|
|
}
|
|
|
|
openLoadSaves() {
|
|
this.showSaveNoti = false;
|
|
this.saveTab = true;
|
|
}
|
|
|
|
async loadSavedFile(file_commit: any) {
|
|
this.showSaveNoti = false;
|
|
this.saveTab = false;
|
|
console.log('loadSavedFile', file_commit, this.department);
|
|
|
|
let country = this.department!;
|
|
|
|
switch (country) {
|
|
case 'tha':
|
|
country = 'Thailand';
|
|
break;
|
|
case 'aus':
|
|
country = 'Australia';
|
|
break;
|
|
case 'mys':
|
|
country = 'Malaysia';
|
|
break;
|
|
case 'alpha-3':
|
|
country = 'alpha-3';
|
|
break;
|
|
}
|
|
|
|
console.log(file_commit.Change_file.split('/')[2]);
|
|
|
|
(
|
|
await this._recipeService.getRecipeOverview({
|
|
offset: this.offset,
|
|
take: this.take,
|
|
search: this.oldSearchStr,
|
|
filename: file_commit.Change_file.split('/')[2],
|
|
country: country,
|
|
materialIds: this.selectMaterialFilter || [],
|
|
})
|
|
).subscribe(({ result, hasMore, totalCount }) => {
|
|
console.log('loadSavedFile', result);
|
|
this._recipeService.setCurrentFile(file_commit.Change_file.split('/')[2]);
|
|
window.location.reload();
|
|
});
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
if (this.currentCountryFilterSubScription) {
|
|
this.currentCountryFilterSubScription.unsubscribe();
|
|
}
|
|
if (this.currentFileFilterSubScription) {
|
|
this.currentFileFilterSubScription.unsubscribe();
|
|
}
|
|
}
|
|
|
|
filterMaterial = (term: string, item: any) =>
|
|
item.name.toLowerCase().includes(term.toLowerCase()) ||
|
|
item.materialId.toString().includes(term);
|
|
|
|
addToCopyList(data: any) {
|
|
if (this.copyList.includes(data)) {
|
|
let index = this.copyList.indexOf(data);
|
|
this.copyList.splice(index, 1);
|
|
} else {
|
|
this.copyList = [...this.copyList, data];
|
|
}
|
|
}
|
|
|
|
async copyToTsv(data: any) {
|
|
await copy(transformToTSV(data))
|
|
.then((value) => {
|
|
console.log('copyToTsv', value);
|
|
})
|
|
.catch((err) => {
|
|
console.log('copyToTsvErr', err);
|
|
});
|
|
}
|
|
|
|
// ------------------------------------ sorting ------------------------------------
|
|
|
|
async sortByHeader(header: string) {
|
|
// productCode
|
|
// name
|
|
// otherName
|
|
// description
|
|
// otherDescription
|
|
// LastUpdate
|
|
|
|
// activate sorting
|
|
console.log('sortByHeader', header);
|
|
//
|
|
|
|
// send to server [/recipe/sort]
|
|
(
|
|
await this._recipeService.sortRecipe(
|
|
await this._recipeService.getCurrentCountry(),
|
|
this._recipeService.getCurrentFile(),
|
|
header
|
|
)
|
|
).subscribe({
|
|
|
|
next: (data: any) => {
|
|
if(data.status == 'OK'){
|
|
window.location.reload();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|