update pagination
This commit is contained in:
parent
3f399dda0e
commit
51642983c6
15 changed files with 1049 additions and 240 deletions
70
client/package-lock.json
generated
70
client/package-lock.json
generated
|
|
@ -16,7 +16,6 @@
|
|||
"@angular/platform-browser": "^16.2.0",
|
||||
"@angular/platform-browser-dynamic": "^16.2.0",
|
||||
"@angular/router": "^16.2.0",
|
||||
"flowbite": "^1.8.1",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
|
|
@ -29,6 +28,7 @@
|
|||
"@types/google.accounts": "^0.0.9",
|
||||
"@types/jasmine": "~4.3.0",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"daisyui": "^3.7.7",
|
||||
"jasmine-core": "~4.6.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
|
|
@ -3122,15 +3122,6 @@
|
|||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@schematics/angular": {
|
||||
"version": "16.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.2.tgz",
|
||||
|
|
@ -4715,6 +4706,12 @@
|
|||
"color-support": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/colord": {
|
||||
"version": "2.9.3",
|
||||
"resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
|
||||
"integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/colorette": {
|
||||
"version": "2.0.20",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
|
||||
|
|
@ -5178,6 +5175,16 @@
|
|||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
},
|
||||
"node_modules/css-selector-tokenizer": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
|
||||
"integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"fastparse": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/css-what": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
|
||||
|
|
@ -5232,6 +5239,26 @@
|
|||
"integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/daisyui": {
|
||||
"version": "3.7.7",
|
||||
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.7.7.tgz",
|
||||
"integrity": "sha512-2/nFdW/6R9MMnR8tTm07jPVyPaZwpUSkVsFAADb7Oq8N2Ynbls57laDdNqxTCUmn0QvcZi01TKl8zQbAwRfw1w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"colord": "^2.9",
|
||||
"css-selector-tokenizer": "^0.8",
|
||||
"postcss": "^8",
|
||||
"postcss-js": "^4",
|
||||
"tailwindcss": "^3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/daisyui"
|
||||
}
|
||||
},
|
||||
"node_modules/data-urls": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
|
||||
|
|
@ -6091,6 +6118,12 @@
|
|||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fastparse": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
|
||||
"integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
|
||||
|
|
@ -6219,15 +6252,6 @@
|
|||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/flowbite": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/flowbite/-/flowbite-1.8.1.tgz",
|
||||
"integrity": "sha512-lXTcO8a6dRTPFpINyOLcATCN/pK1Of/jY4PryklPllAiqH64tSDUsOdQpar3TO59ZXWwugm2e92oaqwH6X90Xg==",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.9.3",
|
||||
"mini-svg-data-uri": "^1.4.3"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||
|
|
@ -8332,14 +8356,6 @@
|
|||
"webpack": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mini-svg-data-uri": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
|
||||
"integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
|
||||
"bin": {
|
||||
"mini-svg-data-uri": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/minimalistic-assert": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
"@angular/platform-browser": "^16.2.0",
|
||||
"@angular/platform-browser-dynamic": "^16.2.0",
|
||||
"@angular/router": "^16.2.0",
|
||||
"flowbite": "^1.8.1",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
|
|
@ -31,6 +30,7 @@
|
|||
"@types/google.accounts": "^0.0.9",
|
||||
"@types/jasmine": "~4.3.0",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"daisyui": "^3.7.7",
|
||||
"jasmine-core": "~4.6.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
|
|
@ -41,4 +41,4 @@
|
|||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "~5.1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { NgModule, inject } from '@angular/core';
|
||||
import { CanActivateFn, Router, RouterModule, Routes } from '@angular/router';
|
||||
import { UserService } from './core/services/user.service';
|
||||
import { Subject, finalize, lastValueFrom, map, takeUntil } from 'rxjs';
|
||||
import { lastValueFrom, map } from 'rxjs';
|
||||
|
||||
const authGuard: CanActivateFn = () => {
|
||||
const userService: UserService = inject(UserService);
|
||||
|
|
@ -74,12 +74,6 @@ const routes: Routes = [
|
|||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
path: '**',
|
||||
pathMatch: 'full',
|
||||
redirectTo: 'dashboard',
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { initFlowbite } from 'flowbite';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
|
|
@ -12,6 +11,5 @@ export class AppComponent implements OnInit {
|
|||
|
||||
ngOnInit(): void {
|
||||
this.titleService.setTitle('Recipe Manager | Tao Bin');
|
||||
initFlowbite();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
type="button"
|
||||
class="inline-flex items-center p-2 text-sm text-gray-500 rounded-lg sm:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200"
|
||||
>
|
||||
<span class="sr-only">Open sidebar</span>
|
||||
<svg
|
||||
class="w-6 h-6"
|
||||
aria-hidden="true"
|
||||
|
|
@ -52,63 +51,66 @@
|
|||
{{ user?.name }}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="flex text-sm bg-gray-800 rounded-full focus:ring-4 focus:ring-gray-300 max-sm:hidden"
|
||||
aria-expanded="false"
|
||||
data-dropdown-toggle="dropdown-user"
|
||||
>
|
||||
<span class="sr-only">Open user menu</span>
|
||||
<img
|
||||
class="sm:h-10 md:h-14 rounded-full cursor-pointer"
|
||||
src="{{ user?.picture }}"
|
||||
loading="lazy"
|
||||
alt="profile picture"
|
||||
/>
|
||||
</button>
|
||||
<div class="dropdown dropdown-bottom dropdown-end">
|
||||
<label
|
||||
tabindex="0"
|
||||
class="btn btn-circle w-14 h-14 focus:ring ring-primary ring-offset-base-100 ring-offset-2 max-sm:hidden"
|
||||
>
|
||||
<div class="avatar">
|
||||
<div class="rounded-full">
|
||||
<img src="{{ user?.picture }}" alt="profile picture" />
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<div
|
||||
tabindex="0"
|
||||
class="dropdown-content z-[-1] menu p-2 shadow bg-base-100 rounded-box w-52 divide-y divide-gray-100"
|
||||
>
|
||||
<div class="px-4 py-3" role="none">
|
||||
<p class="text-sm text-gray-900" role="none">
|
||||
{{ user?.name }}
|
||||
</p>
|
||||
<p
|
||||
class="text-sm font-medium text-gray-900 truncate"
|
||||
role="none"
|
||||
>
|
||||
{{ user?.email }}
|
||||
</p>
|
||||
</div>
|
||||
<ul class="py-1" role="none">
|
||||
<li>
|
||||
<a
|
||||
routerLink="/dashboard"
|
||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
|
||||
role="menuitem"
|
||||
>
|
||||
Dashboard</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
|
||||
role="menuitem"
|
||||
>Settings</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
|
||||
role="menuitem"
|
||||
(click)="logout()"
|
||||
>Sign out</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="z-50 hidden my-4 text-base list-none bg-primary divide-y divide-gray-100 rounded shadow"
|
||||
id="dropdown-user"
|
||||
>
|
||||
<div class="px-4 py-3" role="none">
|
||||
<p class="text-sm text-gray-900" role="none">
|
||||
{{ user?.name }}
|
||||
</p>
|
||||
<p class="text-sm font-medium text-gray-900 truncate" role="none">
|
||||
{{ user?.email }}
|
||||
</p>
|
||||
</div>
|
||||
<ul class="py-1" role="none">
|
||||
<li>
|
||||
<a
|
||||
routerLink="/dashboard"
|
||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
|
||||
role="menuitem"
|
||||
>
|
||||
Dashboard</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
|
||||
role="menuitem"
|
||||
>Settings</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
routerLink="#"
|
||||
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
|
||||
role="menuitem"
|
||||
(click)="logout()"
|
||||
>Sign out</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { DatePipe, NgFor, NgIf } from '@angular/common';
|
|||
import { GoogleButtonComponent } from 'src/app/shared/googleButton/googleButton.component';
|
||||
import { UserService } from '../services/user.service';
|
||||
import { User } from '../models/user.model';
|
||||
import { initFlowbite } from 'flowbite';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
|
||||
interface MenuItem {
|
||||
|
|
@ -40,8 +39,6 @@ export class LayoutComponent implements OnInit {
|
|||
constructor(private _userService: UserService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
initFlowbite();
|
||||
|
||||
this._userService.currentUser
|
||||
.pipe(takeUntil(this.exit$))
|
||||
.subscribe((user) => (this.user = user));
|
||||
|
|
|
|||
|
|
@ -4,12 +4,27 @@ import { BehaviorSubject, Observable, distinctUntilChanged } from 'rxjs';
|
|||
import { Recipe } from '../models/recipe.model';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
interface Pagination {
|
||||
offset: number;
|
||||
take: number;
|
||||
}
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class RecipeService {
|
||||
constructor(private _httpClient: HttpClient) {}
|
||||
|
||||
getRecipes(): Observable<Recipe> {
|
||||
return this._httpClient.get<Recipe>(environment.api + '/recipes', {
|
||||
getRecipes(paginate: Pagination = { take: 10, offset: 0 }): Observable<{
|
||||
recipes: Recipe;
|
||||
hasMore: boolean;
|
||||
}> {
|
||||
return this._httpClient.get<{
|
||||
recipes: Recipe;
|
||||
hasMore: boolean;
|
||||
}>(environment.api + '/recipes', {
|
||||
params: {
|
||||
offset: String(paginate.offset),
|
||||
take: String(paginate.take),
|
||||
},
|
||||
withCredentials: true,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,49 +1,72 @@
|
|||
<main class="relative overflow-auto max-h-[700px] shadow-md sm:rounded-lg">
|
||||
<table
|
||||
*ngIf="isLoaded; else loadingIndicator"
|
||||
class="w-full table-auto text-sm text-left text-gray-500"
|
||||
>
|
||||
<caption
|
||||
class="p-5 text-lg font-semibold text-left text-gray-900 bg-primary"
|
||||
>
|
||||
<div class="flex flex-row">
|
||||
<div class="flex flex-col">
|
||||
<span
|
||||
>Recipe Version {{ recipes?.MachineSetting?.configNumber }} |
|
||||
{{"{{File name}}"}}</span
|
||||
>
|
||||
<main
|
||||
class="relative overflow-auto max-h-[700px] shadow-md sm:rounded-lg"
|
||||
#table
|
||||
>
|
||||
<table *ngIf="isLoaded" class="table">
|
||||
<caption class="p-5 text-lg font-semibold text-left text-gray-900">
|
||||
<div class="divide-y divide-solid divide-gray-400">
|
||||
<div class="flex flex-row py-3">
|
||||
<div class="flex flex-col">
|
||||
<span
|
||||
>Recipe Version {{ recipes?.MachineSetting?.configNumber }} |
|
||||
{{"{{File name}}"}}</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex flex-col ml-auto">
|
||||
<span class=""
|
||||
>Last Updated:
|
||||
{{ recipes?.Timestamp | date : "dd-MMM-yyyy hh:mm:ss" }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col ml-auto">
|
||||
<span class=""
|
||||
>Last Updated:
|
||||
{{ recipes?.Timestamp | date : "dd-MMM-yyyy hh:mm:ss" }}</span
|
||||
>
|
||||
<div class="flex flex-col">
|
||||
<div class="relativ sm:rounded-lg">
|
||||
<div
|
||||
class="flex flex-col items-center justify-between p-4 space-y-3 md:flex-row md:space-y-0 md:space-x-4"
|
||||
>
|
||||
<div class="join">
|
||||
<input
|
||||
class="input input-bordered join-item w-[300px]"
|
||||
placeholder="Product Code, Name or Other Name"
|
||||
/>
|
||||
<button class="btn join-item">Search</button>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button class="btn rounded-lg">View JSON</button>
|
||||
<button class="btn rounded-lg">
|
||||
<svg
|
||||
class="w-6 h-6 text-gray-800 dark:text-white"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 18 20"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="1"
|
||||
d="M15 6V2a.97.97 0 0 0-.933-1H5.828a2 2 0 0 0-1.414.586L1.586 4.414A2 2 0 0 0 1 5.828V18a.969.969 0 0 0 .933 1H14a1 1 0 0 0 1-1M6 1v4a1 1 0 0 1-1 1H1m6 6h9m-1.939-2.768L16.828 12l-2.767 2.768"
|
||||
/>
|
||||
</svg>
|
||||
Export
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</caption>
|
||||
<thead class="text-xs sticky top-0 text-gray-700 uppercase bg-secondary">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3" *ngFor="let head of tableHeads">
|
||||
<th>
|
||||
<label>
|
||||
<input type="checkbox" class="checkbox" />
|
||||
</label>
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3" *ngFor="let header of tableHeads">
|
||||
<div class="flex items-center uppercase">
|
||||
{{ head }}
|
||||
<a href="#"
|
||||
><svg
|
||||
class="w-3 h-3 ml-1.5"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M8.574 11.024h6.852a2.075 2.075 0 0 0 1.847-1.086 1.9 1.9 0 0 0-.11-1.986L13.736 2.9a2.122 2.122 0 0 0-3.472 0L6.837 7.952a1.9 1.9 0 0 0-.11 1.986 2.074 2.074 0 0 0 1.847 1.086Zm6.852 1.952H8.574a2.072 2.072 0 0 0-1.847 1.087 1.9 1.9 0 0 0 .11 1.985l3.426 5.05a2.123 2.123 0 0 0 3.472 0l3.427-5.05a1.9 1.9 0 0 0 .11-1.985 2.074 2.074 0 0 0-1.846-1.087Z"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="flex items-center py-3">
|
||||
<div class="flex items-center text-center uppercase">
|
||||
Actions
|
||||
{{ header }}
|
||||
<a href="#"
|
||||
><svg
|
||||
class="w-3 h-3 ml-1.5"
|
||||
|
|
@ -59,52 +82,65 @@
|
|||
</a>
|
||||
</div>
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
*ngFor="let recipe of recipes!.Recipe01"
|
||||
*ngFor="let recipe of recipes01"
|
||||
class="bg-white la border-b hover:bg-secondary"
|
||||
>
|
||||
<th
|
||||
<th>
|
||||
<label>
|
||||
<input type="checkbox" class="checkbox" />
|
||||
</label>
|
||||
</th>
|
||||
<td
|
||||
scope="row"
|
||||
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap"
|
||||
>
|
||||
{{ recipe.productCode }}
|
||||
</td>
|
||||
<td
|
||||
class="px-6 max-w-fit py-4 font-medium text-gray-900 whitespace-nowrap"
|
||||
>
|
||||
{{ recipe.name }}
|
||||
</th>
|
||||
</td>
|
||||
<td class="px-6 py-4">{{ recipe.otherName }}</td>
|
||||
<td class="px-6 py-4 flex-wrap max-w-xs">{{ recipe.Description }}</td>
|
||||
<td class="px-6 py-4">
|
||||
{{ recipe.LastChange | date : "dd-MMM-yyyy hh:mm:ss" }}
|
||||
</td>
|
||||
<td class="px-6 py-4 flex gap-2">
|
||||
<a
|
||||
href="#"
|
||||
class="font-medium text-blue-600 dark:text-blue-500 hover:underline"
|
||||
>Edit</a
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
class="font-medium text-blue-600 dark:text-blue-500 hover:underline"
|
||||
>Edit</a
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
class="font-medium text-blue-600 dark:text-blue-500 hover:underline"
|
||||
>Edit</a
|
||||
>
|
||||
<td class="px-4 py-4 flex">
|
||||
<div class="cursor-pointer">
|
||||
<svg
|
||||
class="w-6 h-6 text-gray-800 dark:text-white"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="1"
|
||||
d="M7.75 4H19M7.75 4a2.25 2.25 0 0 1-4.5 0m4.5 0a2.25 2.25 0 0 0-4.5 0M1 4h2.25m13.5 6H19m-2.25 0a2.25 2.25 0 0 1-4.5 0m4.5 0a2.25 2.25 0 0 0-4.5 0M1 10h11.25m-4.5 6H19M7.75 16a2.25 2.25 0 0 1-4.5 0m4.5 0a2.25 2.25 0 0 0-4.5 0M1 16h2.25"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<ng-template #loadingIndicator>
|
||||
<div *ngIf="!isLoaded">
|
||||
<div
|
||||
class="flex w-full items-center justify-center h-56 border border-gray-200 rounded-lg bg-gray-50"
|
||||
>
|
||||
<div role="status">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-8 h-8 mr-2 text-gray-200 animate-spin fill-blue-600"
|
||||
class="w-8 h-8 mr-2 text-gray-200 animate-spin fill-amber-600"
|
||||
viewBox="0 0 100 101"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
|
@ -120,67 +156,5 @@
|
|||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
</main>
|
||||
<nav
|
||||
class="flex items-center justify-between pt-4"
|
||||
aria-label="Table navigation"
|
||||
>
|
||||
<span class="text-sm font-normal text-gray-500 dark:text-gray-400"
|
||||
>Showing
|
||||
<span class="font-semibold text-gray-900 dark:text-white">1-10</span> of
|
||||
<span class="font-semibold text-gray-900 dark:text-white">1000</span></span
|
||||
>
|
||||
<ul class="inline-flex -space-x-px text-sm h-8">
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center justify-center px-3 h-8 ml-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-l-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
|
||||
>Previous</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
|
||||
>1</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
|
||||
>2</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
aria-current="page"
|
||||
class="flex items-center justify-center px-3 h-8 text-blue-600 border border-gray-300 bg-blue-50 hover:bg-blue-100 hover:text-blue-700 dark:border-gray-700 dark:bg-gray-700 dark:text-white"
|
||||
>3</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
|
||||
>4</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
|
||||
>5</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 rounded-r-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
|
||||
>Next</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import {
|
||||
AfterContentChecked,
|
||||
AfterRenderRef,
|
||||
AfterViewChecked,
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { UserService } from 'src/app/core/services/user.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { User } from 'src/app/core/models/user.model';
|
||||
import { DatePipe, NgFor, NgIf } from '@angular/common';
|
||||
import { initFlowbite } from 'flowbite';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { delay } from 'rxjs';
|
||||
import { Recipe } from 'src/app/core/models/recipe.model';
|
||||
import { Recipe, Recipe01 } from 'src/app/core/models/recipe.model';
|
||||
import { RecipeService } from 'src/app/core/services/recipe.service';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
|
|
@ -18,8 +24,59 @@ import { RecipeService } from 'src/app/core/services/recipe.service';
|
|||
export class DashboardComponent implements OnInit {
|
||||
userInfo: User | null = null;
|
||||
recipes: Recipe | null = null;
|
||||
tableHeads: string[] = ['Name', 'Other Name', 'Description', 'Last Updated'];
|
||||
recipes01: Recipe01[] | null = null;
|
||||
|
||||
tableHeads: string[] = [
|
||||
'Product Code',
|
||||
'Name',
|
||||
'Other Name',
|
||||
'Description',
|
||||
'Last Updated',
|
||||
];
|
||||
private offset = 0;
|
||||
private take = 10;
|
||||
|
||||
isLoaded: boolean = false;
|
||||
isLoadMore: boolean = false;
|
||||
isHasMore: boolean = true;
|
||||
|
||||
@ViewChild('table', { static: false }) set content(table: ElementRef) {
|
||||
table.nativeElement.addEventListener(
|
||||
'scroll',
|
||||
() => {
|
||||
if (this.isHasMore === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { scrollTop, scrollHeight, clientHeight } = table.nativeElement;
|
||||
const isBottom = scrollTop + clientHeight >= scrollHeight - 10;
|
||||
if (isBottom && !this.isLoadMore) {
|
||||
this.isLoadMore = true;
|
||||
this._recipeService
|
||||
.getRecipes({
|
||||
offset: this.offset,
|
||||
take: this.take,
|
||||
})
|
||||
.subscribe(({ recipes, hasMore }) => {
|
||||
const { Recipe01, ...recipesWithoutRecipe01 } = recipes;
|
||||
if (this.recipes01 && this.isHasMore) {
|
||||
this.recipes01 = [...this.recipes01, ...Recipe01];
|
||||
} else {
|
||||
this.recipes01 = Recipe01;
|
||||
}
|
||||
this.recipes = {
|
||||
...recipesWithoutRecipe01,
|
||||
Recipe01: [],
|
||||
};
|
||||
this.offset += 10;
|
||||
this.isLoadMore = false;
|
||||
this.isHasMore = hasMore;
|
||||
});
|
||||
}
|
||||
},
|
||||
{ passive: true }
|
||||
);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _userService: UserService,
|
||||
|
|
@ -27,16 +84,29 @@ export class DashboardComponent implements OnInit {
|
|||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
initFlowbite();
|
||||
|
||||
this._userService.currentUser.subscribe((user) => {
|
||||
this.userInfo = user;
|
||||
});
|
||||
|
||||
this._recipeService.getRecipes().subscribe((recipes) => {
|
||||
this.recipes = recipes;
|
||||
this.isLoaded = true;
|
||||
console.log(this.recipes);
|
||||
});
|
||||
this._recipeService
|
||||
.getRecipes({
|
||||
offset: this.offset,
|
||||
take: this.take,
|
||||
})
|
||||
.subscribe(({ recipes, hasMore }) => {
|
||||
const { Recipe01, ...recipesWithoutRecipe01 } = recipes;
|
||||
if (this.recipes01 && this.isHasMore) {
|
||||
this.recipes01 = [...this.recipes01, ...Recipe01];
|
||||
} else {
|
||||
this.recipes01 = Recipe01;
|
||||
}
|
||||
this.recipes = {
|
||||
...recipesWithoutRecipe01,
|
||||
Recipe01: [],
|
||||
};
|
||||
this.offset += 10;
|
||||
this.isLoaded = true;
|
||||
this.isHasMore = hasMore;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
client/src/assets/icons/export.svg
Normal file
1
client/src/assets/icons/export.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M240-40q-33 0-56.5-23.5T160-120v-440q0-33 23.5-56.5T240-640h120v80H240v440h480v-440H600v-80h120q33 0 56.5 23.5T800-560v440q0 33-23.5 56.5T720-40H240Zm200-280v-447l-64 64-56-57 160-160 160 160-56 57-64-64v447h-80Z"/></svg>
|
||||
|
After Width: | Height: | Size: 318 B |
|
|
@ -1,14 +1,15 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: "class",
|
||||
content: [
|
||||
"./src/**/*.{html,ts}",
|
||||
"./node_modules/flowbite/**/*.js" // add this line
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
"backgroundColor": {
|
||||
"primary": "#EAE6E1",
|
||||
"secondary": "#F5F5F5",
|
||||
"third": "#F2994A",
|
||||
},
|
||||
"textColor": {
|
||||
"primary": "#513C2F",
|
||||
|
|
@ -18,6 +19,9 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
},
|
||||
plugins: [require("flowbite/plugin")],
|
||||
daisyui: {
|
||||
themes: ["cupcake"]
|
||||
},
|
||||
plugins: [require('daisyui')],
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue