saving with admin and public base

This commit is contained in:
Betteloni 2024-10-13 16:57:31 -03:00
parent 06776d15c4
commit dd1b2763d8
425 changed files with 21493 additions and 11663 deletions

29554
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -40,6 +40,7 @@
"@angular/platform-browser": "^15.2.10",
"@angular/platform-browser-dynamic": "^15.2.10",
"@angular/router": "^15.2.10",
"@apollo/client": "^3.11.4",
"@asymmetrik/ngx-leaflet": "3.0.1",
"@nebular/auth": "11.0.1",
"@nebular/eva-icons": "11.0.1",
@ -47,6 +48,7 @@
"@nebular/theme": "11.0.1",
"@swimlane/ngx-charts": "^14.0.0",
"angular2-chartjs": "0.4.1",
"apollo-angular": "^7.0.2",
"bootstrap": "4.3.1",
"chart.js": "2.7.1",
"ckeditor": "4.7.3",
@ -54,6 +56,7 @@
"core-js": "2.5.1",
"echarts": "^4.9.0",
"eva-icons": "^1.1.3",
"graphql": "^16.9.0",
"intl": "1.2.5",
"ionicons": "2.0.1",
"leaflet": "1.2.0",
@ -62,7 +65,6 @@
"ng2-completer": "^9.0.1",
"ng2-smart-table": "^1.6.0",
"ngx-echarts": "^4.2.2",
"node-sass": "^4.14.1",
"normalize.css": "6.0.0",
"pace-js": "1.0.2",
"roboto-fontface": "0.8.0",

View file

@ -0,0 +1,7 @@
<nb-card>
<nb-card-header>Do you confirm your action?</nb-card-header>
<nb-card-footer>
<button class="cancel" nbButton status="danger" (click)="cancel()">Cancel</button>
<button nbButton status="success" (click)="submit()">Submit</button>
</nb-card-footer>
</nb-card>

View file

@ -0,0 +1,20 @@
import { Component } from '@angular/core';
import { NbDialogRef } from '@nebular/theme';
@Component({
selector: 'ngx-dialog-prompt',
templateUrl: 'dialog-prompt.component.html',
styleUrls: ['dialog-prompt.component.scss'],
})
export class DialogPromptComponent {
constructor(protected ref: NbDialogRef<DialogPromptComponent>) {}
cancel() {
this.ref.close(false);
}
submit() {
this.ref.close(true);
}
}

View file

@ -1,28 +1,45 @@
<div class="header-container">
<div class="logo-container">
<a (click)="toggleSidebar()" href="#" class="sidebar-toggle">
<a *ngIf="menu" (click)="toggleSidebar()" href="#" class="sidebar-toggle">
<nb-icon icon="menu-2-outline"></nb-icon>
</a>
<a class="logo" href="#" (click)="navigateHome()">ngx-<span>admin</span></a>
<a class="logo" href="#" (click)="navigateHome()"
><span>Desapegrow</span></a
>
</div>
<nb-select [selected]="currentTheme" (selectedChange)="changeTheme($event)" status="primary">
<nb-option *ngFor="let theme of themes" [value]="theme.value"> {{ theme.name }}</nb-option>
<nb-select
[selected]="currentTheme"
(selectedChange)="changeTheme($event)"
status="primary"
>
<nb-option *ngFor="let theme of themes" [value]="theme.value">
{{ theme.name }}</nb-option
>
</nb-select>
</div>
<div class="header-container">
<nb-actions size="small">
<nb-action class="control-item">
<nb-search type="rotate-layout"></nb-search>
</nb-action>
<nb-action class="control-item" icon="email-outline"></nb-action>
<nb-action class="control-item" icon="bell-outline"></nb-action>
<nb-action class="user-action" *nbIsGranted="['view', 'user']" >
<nb-user [nbContextMenu]="userMenu"
[onlyPicture]="userPictureOnly"
[name]="user?.name"
[picture]="user?.picture">
<nb-action
class="control-item"
icon="message-circle-outline"
badgeDot
badgeStatus="danger"
badgePosition="top right"
(click)="goToChat()"
></nb-action>
<nb-action class="user-action" *nbIsGranted="['view', 'user']">
<nb-user
[nbContextMenu]="userMenu"
[onlyPicture]="userPictureOnly"
[name]="user?.name"
[picture]="user?.picture"
>
</nb-user>
</nb-action>
</nb-actions>

View file

@ -1,10 +1,11 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { NbMediaBreakpointsService, NbMenuService, NbSidebarService, NbThemeService } from '@nebular/theme';
import { UserData } from '../../../@core/data/users';
import { LayoutService } from '../../../@core/utils';
import { map, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { Router } from '@angular/router';
@Component({
selector: 'ngx-header',
@ -12,7 +13,7 @@ import { Subject } from 'rxjs';
templateUrl: './header.component.html',
})
export class HeaderComponent implements OnInit, OnDestroy {
@Input() menu: boolean = true;
private destroy$: Subject<void> = new Subject<void>();
userPictureOnly: boolean = false;
user: any;
@ -45,7 +46,8 @@ export class HeaderComponent implements OnInit, OnDestroy {
private themeService: NbThemeService,
private userService: UserData,
private layoutService: LayoutService,
private breakpointService: NbMediaBreakpointsService) {
private breakpointService: NbMediaBreakpointsService,
private router: Router) {
}
ngOnInit() {
@ -91,4 +93,11 @@ export class HeaderComponent implements OnInit, OnDestroy {
this.menuService.navigateHome();
return false;
}
goToChat() {
this.router.navigate([
"admin",
"chat"
]);
}
}

View file

@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { Component, Input } from '@angular/core';
@Component({
selector: 'ngx-one-column-layout',
@ -6,10 +6,10 @@ import { Component } from '@angular/core';
template: `
<nb-layout windowMode>
<nb-layout-header fixed>
<ngx-header></ngx-header>
<ngx-header [menu]="menu"></ngx-header>
</nb-layout-header>
<nb-sidebar class="menu-sidebar" tag="menu-sidebar" responsive>
<nb-sidebar *ngIf="menu" class="menu-sidebar" tag="menu-sidebar" responsive>
<ng-content select="nb-menu"></ng-content>
</nb-sidebar>
@ -23,4 +23,6 @@ import { Component } from '@angular/core';
</nb-layout>
`,
})
export class OneColumnLayoutComponent {}
export class OneColumnLayoutComponent {
@Input() menu: boolean = true;
}

View file

@ -12,6 +12,7 @@ import {
NbSelectModule,
NbIconModule,
NbThemeModule,
NbCardModule,
} from '@nebular/theme';
import { NbEvaIconsModule } from '@nebular/eva-icons';
import { NbSecurityModule } from '@nebular/security';
@ -38,6 +39,7 @@ import { DEFAULT_THEME } from './styles/theme.default';
import { COSMIC_THEME } from './styles/theme.cosmic';
import { CORPORATE_THEME } from './styles/theme.corporate';
import { DARK_THEME } from './styles/theme.dark';
import { DialogPromptComponent } from './components/dialogs/dialog-name-prompt/dialog-prompt.component';
const NB_MODULES = [
NbLayoutModule,
@ -52,6 +54,7 @@ const NB_MODULES = [
NbSelectModule,
NbIconModule,
NbEvaIconsModule,
NbCardModule,
];
const COMPONENTS = [
HeaderComponent,
@ -61,6 +64,7 @@ const COMPONENTS = [
OneColumnLayoutComponent,
ThreeColumnsLayoutComponent,
TwoColumnsLayoutComponent,
DialogPromptComponent
];
const PIPES = [
CapitalizePipe,

View file

@ -4,13 +4,13 @@ export const MENU_ITEMS: NbMenuItem[] = [
{
title: 'E-commerce',
icon: 'shopping-cart-outline',
link: '/pages/dashboard',
link: '/admin/dashboard',
home: true,
},
{
title: 'IoT Dashboard',
icon: 'home-outline',
link: '/pages/iot-dashboard',
link: '/admin/iot-dashboard',
},
{
title: 'FEATURES',
@ -22,24 +22,24 @@ export const MENU_ITEMS: NbMenuItem[] = [
children: [
{
title: 'Stepper',
link: '/pages/layout/stepper',
link: '/admin/layout/stepper',
},
{
title: 'List',
link: '/pages/layout/list',
link: '/admin/layout/list',
},
{
title: 'Infinite List',
link: '/pages/layout/infinite-list',
link: '/admin/layout/infinite-list',
},
{
title: 'Accordion',
link: '/pages/layout/accordion',
link: '/admin/layout/accordion',
},
{
title: 'Tabs',
pathMatch: 'prefix',
link: '/pages/layout/tabs',
link: '/admin/layout/tabs',
},
],
},
@ -49,42 +49,98 @@ export const MENU_ITEMS: NbMenuItem[] = [
children: [
{
title: 'Form Inputs',
link: '/pages/forms/inputs',
link: '/admin/forms/inputs',
},
{
title: 'Form Layouts',
link: '/pages/forms/layouts',
link: '/admin/forms/layouts',
},
{
title: 'Buttons',
link: '/pages/forms/buttons',
link: '/admin/forms/buttons',
},
{
title: 'Datepicker',
link: '/pages/forms/datepicker',
link: '/admin/forms/datepicker',
},
],
},
{
title: 'Banner',
icon: 'edit-2-outline',
children: [
{
title: 'Edit',
link: '/admin/banner/edit',
},
{
title: 'Create',
link: '/admin/banner/create',
},
],
},
{
title: 'Brand',
icon: 'edit-2-outline',
children: [
{
title: 'Edit',
link: '/admin/brand/edit',
},
{
title: 'Create',
link: '/admin/brand/create',
},
],
},
{
title: 'Category',
icon: 'edit-2-outline',
children: [
{
title: 'Edit',
link: '/admin/category/edit',
},
{
title: 'Create',
link: '/admin/category/create',
}
],
},
{
title: 'Sub Category',
icon: 'edit-2-outline',
children: [
{
title: 'Edit',
link: '/admin/sub-category/edit',
},
{
title: 'Create',
link: '/admin/sub-category/create',
}
],
},
{
title: 'UI Features',
icon: 'keypad-outline',
link: '/pages/ui-features',
link: '/admin/ui-features',
children: [
{
title: 'Grid',
link: '/pages/ui-features/grid',
link: '/admin/ui-features/grid',
},
{
title: 'Icons',
link: '/pages/ui-features/icons',
link: '/admin/ui-features/icons',
},
{
title: 'Typography',
link: '/pages/ui-features/typography',
link: '/admin/ui-features/typography',
},
{
title: 'Animated Searches',
link: '/pages/ui-features/search-fields',
link: '/admin/ui-features/search-fields',
},
],
},
@ -94,23 +150,23 @@ export const MENU_ITEMS: NbMenuItem[] = [
children: [
{
title: 'Dialog',
link: '/pages/modal-overlays/dialog',
link: '/admin/modal-overlays/dialog',
},
{
title: 'Window',
link: '/pages/modal-overlays/window',
link: '/admin/modal-overlays/window',
},
{
title: 'Popover',
link: '/pages/modal-overlays/popover',
link: '/admin/modal-overlays/popover',
},
{
title: 'Toastr',
link: '/pages/modal-overlays/toastr',
link: '/admin/modal-overlays/toastr',
},
{
title: 'Tooltip',
link: '/pages/modal-overlays/tooltip',
link: '/admin/modal-overlays/tooltip',
},
],
},
@ -120,27 +176,27 @@ export const MENU_ITEMS: NbMenuItem[] = [
children: [
{
title: 'Calendar',
link: '/pages/extra-components/calendar',
link: '/admin/extra-components/calendar',
},
{
title: 'Progress Bar',
link: '/pages/extra-components/progress-bar',
link: '/admin/extra-components/progress-bar',
},
{
title: 'Spinner',
link: '/pages/extra-components/spinner',
link: '/admin/extra-components/spinner',
},
{
title: 'Alert',
link: '/pages/extra-components/alert',
link: '/admin/extra-components/alert',
},
{
title: 'Calendar Kit',
link: '/pages/extra-components/calendar-kit',
link: '/admin/extra-components/calendar-kit',
},
{
title: 'Chat',
link: '/pages/extra-components/chat',
link: '/admin/extra-components/chat',
},
],
},
@ -150,19 +206,19 @@ export const MENU_ITEMS: NbMenuItem[] = [
children: [
{
title: 'Google Maps',
link: '/pages/maps/gmaps',
link: '/admin/maps/gmaps',
},
{
title: 'Leaflet Maps',
link: '/pages/maps/leaflet',
link: '/admin/maps/leaflet',
},
{
title: 'Bubble Maps',
link: '/pages/maps/bubble',
link: '/admin/maps/bubble',
},
{
title: 'Search Maps',
link: '/pages/maps/searchmap',
link: '/admin/maps/searchmap',
},
],
},
@ -172,15 +228,15 @@ export const MENU_ITEMS: NbMenuItem[] = [
children: [
{
title: 'Echarts',
link: '/pages/charts/echarts',
link: '/admin/charts/echarts',
},
{
title: 'Charts.js',
link: '/pages/charts/chartjs',
link: '/admin/charts/chartjs',
},
{
title: 'D3',
link: '/pages/charts/d3',
link: '/admin/charts/d3',
},
],
},
@ -190,11 +246,11 @@ export const MENU_ITEMS: NbMenuItem[] = [
children: [
{
title: 'TinyMCE',
link: '/pages/editors/tinymce',
link: '/admin/editors/tinymce',
},
{
title: 'CKEditor',
link: '/pages/editors/ckeditor',
link: '/admin/editors/ckeditor',
},
],
},
@ -204,11 +260,11 @@ export const MENU_ITEMS: NbMenuItem[] = [
children: [
{
title: 'Smart Table',
link: '/pages/tables/smart-table',
link: '/admin/tables/smart-table',
},
{
title: 'Tree Grid',
link: '/pages/tables/tree-grid',
link: '/admin/tables/tree-grid',
},
],
},
@ -218,7 +274,7 @@ export const MENU_ITEMS: NbMenuItem[] = [
children: [
{
title: '404',
link: '/pages/miscellaneous/404',
link: '/admin/miscellaneous/404',
},
],
},

View file

@ -1,14 +1,14 @@
import { RouterModule, Routes } from '@angular/router';
import { NgModule } from '@angular/core';
import { PagesComponent } from './pages.component';
import { AdminComponent } from './admin.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { ECommerceComponent } from './e-commerce/e-commerce.component';
import { NotFoundComponent } from './miscellaneous/not-found/not-found.component';
const routes: Routes = [{
path: '',
component: PagesComponent,
component: AdminComponent,
children: [
{
path: 'dashboard',
@ -63,6 +63,31 @@ const routes: Routes = [{
loadChildren: () => import('./tables/tables.module')
.then(m => m.TablesModule),
},
{
path: 'banner',
loadChildren: () => import('./banner/banner.module')
.then(m => m.BannerModule),
},
{
path: 'brand',
loadChildren: () => import('./brand/brand.module')
.then(m => m.BrandModule),
},
{
path: 'chat',
loadChildren: () => import('./chat/chat.module')
.then(m => m.ChatModule),
},
{
path: 'category',
loadChildren: () => import('./category/category.module')
.then(m => m.CategoryModule),
},
{
path: 'sub-category',
loadChildren: () => import('./sub-category/sub-category.module')
.then(m => m.SubCategoryModule),
},
{
path: 'miscellaneous',
loadChildren: () => import('./miscellaneous/miscellaneous.module')
@ -84,5 +109,5 @@ const routes: Routes = [{
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class PagesRoutingModule {
export class AdminRoutingModule {
}

View file

@ -1,10 +1,10 @@
import { Component } from '@angular/core';
import { MENU_ITEMS } from './pages-menu';
import { MENU_ITEMS } from './admin-menu';
@Component({
selector: 'ngx-pages',
styleUrls: ['pages.component.scss'],
selector: 'ngx-admin',
styleUrls: ['admin.component.scss'],
template: `
<ngx-one-column-layout>
<nb-menu [items]="menu"></nb-menu>
@ -12,7 +12,7 @@ import { MENU_ITEMS } from './pages-menu';
</ngx-one-column-layout>
`,
})
export class PagesComponent {
export class AdminComponent {
menu = MENU_ITEMS;
}

View file

@ -2,24 +2,30 @@ import { NgModule } from '@angular/core';
import { NbMenuModule } from '@nebular/theme';
import { ThemeModule } from '../@theme/theme.module';
import { PagesComponent } from './pages.component';
import { AdminComponent } from './admin.component';
import { DashboardModule } from './dashboard/dashboard.module';
import { ECommerceModule } from './e-commerce/e-commerce.module';
import { PagesRoutingModule } from './pages-routing.module';
import { AdminRoutingModule } from './admin-routing.module';
import { MiscellaneousModule } from './miscellaneous/miscellaneous.module';
import { CategoryModule } from './category/category.module';
import { SubCategoryModule } from './sub-category/sub-category.module';
import { BrandModule } from './brand/brand.module';
@NgModule({
imports: [
PagesRoutingModule,
AdminRoutingModule,
ThemeModule,
NbMenuModule,
DashboardModule,
ECommerceModule,
MiscellaneousModule,
CategoryModule,
SubCategoryModule,
BrandModule
],
declarations: [
PagesComponent,
AdminComponent,
],
})
export class PagesModule {
export class AdminModule {
}

View file

@ -0,0 +1,10 @@
<nb-card>
<nb-card-header>
Banners
</nb-card-header>
<nb-card-body>
<ng2-smart-table [settings]="settings" [source]="source" (edit)="onEdit($event)" (userRowSelect)="onEdit($event)">
</ng2-smart-table>
</nb-card-body>
</nb-card>

View file

@ -0,0 +1,92 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { LocalDataSource } from "ng2-smart-table";
import { BannerService } from "../banner.service";
import { Router } from "@angular/router";
import { Banner } from "../banner.model";
import { Subject } from "rxjs";
import { takeUntil, tap } from "rxjs/operators";
@Component({
selector: "ngx-banner-edit",
templateUrl: "./banner-edit.component.html",
styleUrls: ["./banner-edit.component.scss"],
})
export class BannerEditComponent implements OnInit, OnDestroy {
private destroy$: Subject<void> = new Subject<void>();
settings = {
mode: "external",
actions: {
add: false,
delete: false,
},
edit: {
editButtonContent: '<i class="nb-edit"></i>',
saveButtonContent: '<i class="nb-checkmark"></i>',
cancelButtonContent: '<i class="nb-close"></i>',
},
columns: {
id: {
title: "ID",
type: "string",
editable: false,
},
title: {
title: "Title",
type: "string",
editable: false,
},
sorting: {
title: "Sorting",
type: "number",
editable: false,
},
clickCount: {
title: "Click Count",
type: "number",
editable: false,
},
viewCount: {
title: "View Count",
type: "number",
editable: false,
},
isActive: {
title: "Is Active",
type: "boolean",
editable: false,
},
},
};
source: LocalDataSource = new LocalDataSource();
loading: boolean = true;
banners: Banner[];
constructor(private bannerService: BannerService, private router: Router) {}
ngOnInit(): void {
this.bannerService
.listBanners()
.pipe(
tap(() => {
this.loading = true;
}),
takeUntil(this.destroy$)
)
.subscribe(({ data, loading }) => {
this.loading = loading;
this.banners = data.listBanners;
this.source.load(this.banners);
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
onEdit(event): void {
this.router.navigate(["admin", "banner", "edit", event.data.id]);
}
}

View file

@ -0,0 +1,37 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { BannerComponent } from './banner.component';
import { BannerEditComponent } from './banner-edit/banner-edit.component';
import { BannerUpsertComponent } from './banner-upsert/banner-upsert.component';
const routes: Routes = [{
path: '',
component: BannerComponent,
children: [
{
path: 'edit',
component: BannerEditComponent,
},
{
path: 'edit/:id',
component: BannerUpsertComponent,
},
{
path: 'create',
component: BannerUpsertComponent,
},
],
}];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class BannerRoutingModule { }
export const routedComponents = [
BannerComponent,
BannerEditComponent,
BannerUpsertComponent
];

View file

@ -0,0 +1,106 @@
<div class="row">
<div class="col-md-12">
<nb-card *ngIf="!loading">
<nb-card-header>Banner {{ banner.id }}</nb-card-header>
<nb-card-body>
<div *ngIf="banner.id" class="summary-container">
<div>
<div>Created At</div>
<div class="h6">{{ banner.createdAt | date: 'dd:MM:YYYY HH:mm:ss' }}</div>
</div>
<div>
<div>Click Count</div>
<div class="h6">{{ banner.clickCount || 0 }}</div>
</div>
<div>
<div>View Count</div>
<div class="h6">{{ banner.viewCount || 0 }}</div>
</div>
</div>
<form (ngSubmit)="onSubmit(bannerForm.form)" #bannerForm="ngForm">
<div class="form-group">
<label for="bannerTitle" class="label">Title</label>
<input
type="text"
nbInput
fullWidth
id="bannerTitle"
placeholder="Title"
required
[(ngModel)]="banner.title"
name="title"
/>
</div>
<div class="form-group">
<label for="bannerText" class="label">Text</label>
<input
type="text"
nbInput
fullWidth
id="bannerText"
placeholder="Text"
required
[(ngModel)]="banner.text"
name="text"
/>
</div>
<div class="form-group">
<label for="bannerSorting" class="label">Sorting</label>
<input
type="number"
nbInput
fullWidth
id="bannerSorting"
placeholder="Sorting"
required
[(ngModel)]="banner.sorting"
name="sorting"
/>
</div>
<div class="form-group">
<label for="bannerLink" class="label">Link</label>
<input
type="text"
nbInput
fullWidth
id="bannerLink"
placeholder="Link"
required
[(ngModel)]="banner.link"
name="link"
/>
</div>
<div class="form-group">
<label for="bannerImgUrl" class="label">ImgUrl</label>
<input
type="text"
nbInput
fullWidth
id="bannerImgUrl"
placeholder="ImgUrl"
required
[(ngModel)]="banner.imgUrl"
name="imgUrl"
/>
</div>
<div class="form-group">
<nb-checkbox required [(ngModel)]="banner.isActive" name="isActive"
>Active</nb-checkbox
>
</div>
<div class="form-group ">
<button
type="submit"
nbButton
status="primary"
[disabled]="!bannerForm.form.valid"
>
Submit
</button>
</div>
</form>
</nb-card-body>
</nb-card>
</div>
</div>

View file

@ -0,0 +1,31 @@
@import '../../../@theme/styles/themes';
nb-checkbox {
margin-bottom: 1rem;
}
.form-inline [fullWidth] {
flex: 1;
}
.form-inline > * {
margin: 0 1.5rem 1.5rem 0;
}
nb-card.inline-form-card nb-card-body {
padding-bottom: 0;
}
@include nb-install-component() {
.summary-container {
display: flex;
flex-wrap: wrap;
flex: 1;
background-color: nb-theme(background-basic-color-2);
justify-content: space-between;
padding: 1.5rem 4rem 1rem;
border: 1px solid nb-theme(border-basic-color-3);
border-left: none;
border-right: none;
}
}

View file

@ -0,0 +1,116 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute, ParamMap, Router } from "@angular/router";
import { BannerService } from "../banner.service";
import { Banner } from "../banner.model";
import { NgForm } from "@angular/forms";
import { takeUntil, tap } from "rxjs/operators";
import {
NbToastrService,
NbComponentStatus,
NbGlobalPhysicalPosition,
} from "@nebular/theme";
import { Subject } from "rxjs";
@Component({
selector: "ngx-banner-upsert",
styleUrls: ["./banner-upsert.component.scss"],
templateUrl: "./banner-upsert.component.html",
})
export class BannerUpsertComponent implements OnInit, OnDestroy {
private destroy$: Subject<void> = new Subject<void>();
id: string;
loading: boolean = false;
banner: Banner;
constructor(
private route: ActivatedRoute,
private router: Router,
private toastrService: NbToastrService,
private bannerService: BannerService
) {
this.banner = new Banner();
}
ngOnInit(): void {
this.route.paramMap.subscribe((params: ParamMap) => {
this.id = params.get("id");
if (this.id) {
this.bannerService
.findUniqueBanner(this.id)
.pipe(
tap(() => {
this.loading = true;
}),
takeUntil(this.destroy$)
)
.subscribe(({ data, loading }) => {
this.loading = loading;
this.banner = Object.assign({}, data.findUniqueBanner);
});
}
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
onSubmit(form: NgForm) {
const banner = {
...form.value,
id: this.id,
} as Banner;
if (this.id) {
this.bannerService
.updateBanner(banner)
.pipe(takeUntil(this.destroy$))
.subscribe(
({ data }) => {
this.toastrService.show(
null,
`Banner has been successfully updated`,
{
status: "success",
}
);
},
(error) => {
this.toastrService.show(error.toString(), `Something went wrong`, {
status: "danger",
});
}
);
} else {
this.bannerService
.createBanner(banner)
.pipe(takeUntil(this.destroy$))
.subscribe(
({ data }) => {
this.toastrService.show(
null,
`Banner has been successfully created`,
{
status: "success",
}
);
this.router.navigate([
"admin",
"banner",
"edit",
data.createBanner.id,
]);
},
(error) => {
this.toastrService.show(error.toString(), `Something went wrong`, {
status: "danger",
});
}
);
}
}
}

View file

@ -0,0 +1,8 @@
import { Component } from '@angular/core';
@Component({
selector: 'ngx-banner',
template: `<router-outlet></router-outlet>`,
})
export class BannerComponent {
}

View file

@ -0,0 +1,16 @@
export class Banner {
id!: string;
title!: string;
text!: string;
imgUrl!: string | null;
link!: string | null;
createdAt!: Date;
isActive!: boolean;
sorting!: number;
viewCount!: number | null;
clickCount!: number | null;
constructor() {
this.isActive = false;
}
}

View file

@ -0,0 +1,47 @@
import { NgModule } from '@angular/core';
import {
NbActionsModule,
NbButtonModule,
NbCardModule,
NbCheckboxModule,
NbDatepickerModule,
NbIconModule,
NbInputModule,
NbRadioModule,
NbSelectModule,
NbUserModule,
NbTreeGridModule
} from '@nebular/theme';
import { Ng2SmartTableModule } from 'ng2-smart-table';
import { ThemeModule } from '../../@theme/theme.module';
import { BannerRoutingModule, routedComponents } from './banner-routing.module';
import { BannerService } from './banner.service';
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [
NbCardModule,
NbTreeGridModule,
NbIconModule,
NbInputModule,
ThemeModule,
BannerRoutingModule,
Ng2SmartTableModule,
FormsModule,
NbButtonModule,
NbActionsModule,
NbUserModule,
NbCheckboxModule,
NbRadioModule,
NbDatepickerModule,
NbSelectModule,
],
declarations: [
...routedComponents
],
providers: [
BannerService,
],
})
export class BannerModule { }

View file

@ -0,0 +1,66 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { delay, map } from 'rxjs/operators';
import { Apollo } from 'apollo-angular';
import { FIND_UNIQUE_BANNER, LIST_BANNERS } from './graphql/queries';
import { Banner } from './banner.model';
import { CREATE_BANNER, UPDATE_BANNER } from './graphql/mutations';
const TOTAL_PAGES = 7;
export class NewsPost {
title: string;
link: string;
creator: string;
text: string;
}
@Injectable()
export class BannerService {
constructor(private http: HttpClient, private readonly apollo: Apollo) {}
load(page: number, pageSize: number): Observable<NewsPost[]> {
const startIndex = ((page - 1) % TOTAL_PAGES) * pageSize;
return this.http
.get<NewsPost[]>('assets/data/news.json')
.pipe(
map(news => news.splice(startIndex, pageSize)),
delay(1500),
);
}
listBanners(): Observable<any> {
return this.apollo
.watchQuery<Banner>({
query: LIST_BANNERS(),
})
.valueChanges
}
findUniqueBanner(id: Banner["id"]): Observable<any> {
return this.apollo
.watchQuery<Banner>({
query: FIND_UNIQUE_BANNER(id),
})
.valueChanges
}
createBanner(banner: Banner) {
console.log(CREATE_BANNER(banner));
return this.apollo
.mutate<any>({
mutation: CREATE_BANNER(banner),
});
}
updateBanner(banner: Banner) {
console.log(UPDATE_BANNER(banner));
return this.apollo
.mutate({
mutation: UPDATE_BANNER(banner),
});
}
}

View file

@ -0,0 +1,46 @@
import { gql } from "apollo-angular";
import { Banner } from "../banner.model";
export const UPDATE_BANNER = (banner: Banner) => gql`
mutation UpdateBanner{
updateBanner(
data: {
title: { set: "${banner.title}" }
text: { set: "${banner.text}" }
sorting: { set: ${banner.sorting} }
link: { set: "${banner.link}" }
imgUrl: { set: "${banner.imgUrl}" }
isActive: { set: ${banner.isActive} }
}
where: { id: "${banner.id}" }
) {
clickCount
createdAt
id
imgUrl
isActive
link
sorting
text
title
viewCount
}
}
`;
export const CREATE_BANNER = (banner: Banner) => gql`
mutation CreateBanner {
createBanner(
data: {
title: "${banner.title}"
text: "${banner.text}"
sorting: ${banner.sorting}
link: "${banner.link}"
isActive: ${banner.isActive}
imgUrl: "${banner.imgUrl}"
}
) {
id
}
}
`;

View file

@ -0,0 +1,32 @@
import { gql } from "apollo-angular";
export const LIST_BANNERS = () => gql`
query ListBanners {
listBanners {
clickCount
createdAt
id
isActive
sorting
title
viewCount
}
}
`;
export const FIND_UNIQUE_BANNER = (id: string) =>
gql`
query FindUniqueBanner {
findUniqueBanner(where: { id: "${id}" }) {
clickCount
createdAt
id
imgUrl
isActive
link
sorting
text
title
viewCount
}
}`;

View file

@ -0,0 +1,7 @@
export class BrandCount {
products?: number;
constructor(){
this.products = 0;
}
}

View file

@ -0,0 +1,10 @@
<nb-card>
<nb-card-header>
Categories
</nb-card-header>
<nb-card-body>
<ng2-smart-table [settings]="settings" [source]="source" (edit)="onEdit($event)" (userRowSelect)="onEdit($event)">
</ng2-smart-table>
</nb-card-body>
</nb-card>

View file

@ -0,0 +1,7 @@
@import '../../../@theme/styles/themes';
@include nb-install-component() {
nb-card {
transform: translate3d(0, 0, 0);
}
}

View file

@ -0,0 +1,71 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { LocalDataSource } from "ng2-smart-table";
import { BrandService } from "../brand.service";
import { Router } from "@angular/router";
import { Brand } from "../brand.model";
import { Subject } from "rxjs";
import { takeUntil, tap } from "rxjs/operators";
@Component({
selector: "ngx-brand-edit",
templateUrl: "./brand-edit.component.html",
styleUrls: ["./brand-edit.component.scss"],
})
export class BrandEditComponent implements OnInit, OnDestroy {
private destroy$: Subject<void> = new Subject<void>();
settings = {
mode: 'external',
actions: {
add: false,
delete: false,
},
edit: {
editButtonContent: '<i class="nb-edit"></i>',
saveButtonContent: '<i class="nb-checkmark"></i>',
cancelButtonContent: '<i class="nb-close"></i>',
},
columns: {
id: {
title: "ID",
type: "string",
editable: false,
},
name: {
title: "Name",
type: "string",
editable: false,
}
},
};
source: LocalDataSource = new LocalDataSource();
loading: boolean = true;
brands: Brand[];
constructor(private brandService: BrandService, private router: Router) {
}
ngOnInit(): void {
this.brandService.listBrands()
.pipe(
tap(() => {
this.loading = true;
}),
takeUntil(this.destroy$)
).subscribe(({ data, loading }) => {
this.loading = loading;
this.brands = data.listBrands;
this.source.load(this.brands);
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
onEdit(event): void {
this.router.navigate(["admin", "brand", "edit", event.data.id]);
}
}

View file

@ -0,0 +1,37 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { BrandComponent } from './brand.component';
import { BrandEditComponent } from './brand-edit/brand-edit.component';
import { BrandUpsertComponent } from './brand-upsert/brand-upsert.component';
const routes: Routes = [{
path: '',
component: BrandComponent,
children: [
{
path: 'edit',
component: BrandEditComponent,
},
{
path: 'edit/:id',
component: BrandUpsertComponent,
},
{
path: 'create',
component: BrandUpsertComponent,
},
],
}];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class BrandRoutingModule { }
export const routedComponents = [
BrandComponent,
BrandEditComponent,
BrandUpsertComponent
];

View file

@ -0,0 +1,58 @@
<div class="row">
<div class="col-md-12">
<nb-card *ngIf="!loading">
<nb-card-header>
<nb-icon (click)="goBackToList()" [icon]="'arrow-ios-back-outline'" pack="eva"></nb-icon>
Brand {{ brand.id }}</nb-card-header>
<nb-card-body>
<div *ngIf="brand.id" class="summary-container">
<div>
<div>Created At</div>
<div class="h6">{{ brand.createdAt | date: 'dd:MM:YYYY HH:mm:ss' }}</div>
</div>
<div>
<div>Products Count</div>
<div class="h6">{{ brand._count?.products || 0 }}</div>
</div>
</div>
<form (ngSubmit)="onSubmit(brandForm.form)" #brandForm="ngForm">
<div class="form-group">
<label for="brandName" class="label">Name</label>
<input
type="text"
nbInput
fullWidth
id="brandName"
placeholder="Name"
required
[(ngModel)]="brand.name"
name="name"
/>
</div>
<div class="form-group buttons-row">
<button
type="submit"
nbButton
status="primary"
[disabled]="!brandForm.form.valid"
>
Submit
</button>
<button
*ngIf="brand.id"
type="button"
(click)="onDelete()"
nbButton
status="danger"
>
Delete
</button>
</div>
</form>
</nb-card-body>
</nb-card>
</div>
</div>

View file

@ -0,0 +1,43 @@
@import "../../../@theme/styles/themes";
nb-checkbox {
margin-bottom: 1rem;
}
nb-icon {
cursor: pointer;
}
.form-inline [fullWidth] {
flex: 1;
}
.form-inline > * {
margin: 0 1.5rem 1.5rem 0;
}
nb-card.inline-form-card nb-card-body {
padding-bottom: 0;
}
@include nb-install-component() {
.summary-container {
display: flex;
flex-wrap: wrap;
flex: 1;
background-color: nb-theme(background-basic-color-2);
justify-content: space-between;
padding: 1.5rem 4rem 1rem;
border: 1px solid nb-theme(border-basic-color-3);
border-left: none;
border-right: none;
}
.buttons-row {
margin: -0.5rem;
}
button[nbButton] {
margin: 0.5rem;
}
}

View file

@ -0,0 +1,157 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute, ParamMap, Router } from "@angular/router";
import { BrandService } from "../brand.service";
import { Brand } from "../brand.model";
import { NgForm } from "@angular/forms";
import { takeUntil, tap } from "rxjs/operators";
import {
NbDialogService,
NbToastrService,
} from "@nebular/theme";
import { Subject } from "rxjs";
import { DialogPromptComponent } from "../../../@theme/components/dialogs/dialog-name-prompt/dialog-prompt.component";
@Component({
selector: "ngx-brand-upsert",
styleUrls: ["./brand-upsert.component.scss"],
templateUrl: "./brand-upsert.component.html",
})
export class BrandUpsertComponent implements OnInit, OnDestroy {
private destroy$: Subject<void> = new Subject<void>();
id: string;
loading: boolean = false;
brand: Brand;
constructor(
private route: ActivatedRoute,
private router: Router,
private toastrService: NbToastrService,
private dialogService: NbDialogService,
private brandService: BrandService
) {
this.brand = new Brand();
}
ngOnInit(): void {
this.route.paramMap.subscribe((params: ParamMap) => {
this.id = params.get("id");
if (this.id) {
this.brandService
.findUniqueBrand(this.id)
.pipe(
tap(() => {
this.loading = true;
}),
takeUntil(this.destroy$)
)
.subscribe(({ data, loading }) => {
this.loading = loading;
this.brand = Object.assign({}, data.findUniqueBrand);
});
}
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
onSubmit(form: NgForm) {
const brand = {
...form.value,
id: this.id
} as Brand;
if (this.id) {
this.brandService
.updateBrand(brand)
.pipe(takeUntil(this.destroy$))
.subscribe(
({ data }) => {
this.toastrService.show(
null,
`Brand has been successfully updated`,
{
status: "success",
}
);
},
(error) => {
this.toastrService.show(error.toString(), `Something went wrong`, {
status: "danger",
});
}
);
} else {
this.brandService
.createBrand(brand)
.pipe(takeUntil(this.destroy$))
.subscribe(
({ data }) => {
this.toastrService.show(
null,
`Brand has been successfully created`,
{
status: "success",
}
);
this.router.navigate([
"admin",
"brand",
"edit",
data.createBrand.id,
]);
},
(error) => {
this.toastrService.show(error.toString(), `Something went wrong`, {
status: "danger",
});
}
);
}
}
onDelete(){
if (!this.id) return;
this.dialogService.open(DialogPromptComponent)
.onClose.subscribe(result => result && this.onDeleteConfirmation());
}
onDeleteConfirmation() {
if (!this.id) return;
this.brandService
.deleteBrand(this.id)
.pipe(takeUntil(this.destroy$))
.subscribe(
({ data }) => {
this.toastrService.show(
null,
`Brand has been successfully deleted`,
{
status: "success",
}
);
this.goBackToList()
},
(error) => {
this.toastrService.show(error.toString(), `Something went wrong`, {
status: "danger",
});
}
);
}
goBackToList() {
this.router.navigate([
"admin",
"brand",
"edit"
]);
}
}

View file

@ -0,0 +1,8 @@
import { Component } from '@angular/core';
@Component({
selector: 'ngx-brand',
template: `<router-outlet></router-outlet>`,
})
export class BrandComponent {
}

View file

@ -0,0 +1,13 @@
import { BrandCount } from "./brand-count.model";
export class Brand {
id!: string;
name!: string;
createdAt!: Date;
updatedAt!: Date | null;
_count?: BrandCount;
constructor() {
this._count = new BrandCount();
}
}

View file

@ -0,0 +1,49 @@
import { NgModule } from '@angular/core';
import {
NbActionsModule,
NbButtonModule,
NbCardModule,
NbCheckboxModule,
NbDatepickerModule,
NbIconModule,
NbInputModule,
NbRadioModule,
NbSelectModule,
NbUserModule,
NbTreeGridModule,
NbListModule
} from '@nebular/theme';
import { Ng2SmartTableModule } from 'ng2-smart-table';
import { ThemeModule } from '../../@theme/theme.module';
import { BrandRoutingModule, routedComponents } from './brand-routing.module';
import { BrandService } from './brand.service';
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [
NbCardModule,
NbTreeGridModule,
NbIconModule,
NbInputModule,
ThemeModule,
BrandRoutingModule,
Ng2SmartTableModule,
FormsModule,
NbButtonModule,
NbActionsModule,
NbUserModule,
NbCheckboxModule,
NbRadioModule,
NbDatepickerModule,
NbSelectModule,
NbListModule
],
declarations: [
...routedComponents
],
providers: [
BrandService,
],
})
export class BrandModule { }

View file

@ -0,0 +1,50 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Apollo } from 'apollo-angular';
import { FIND_UNIQUE_BRAND, LIST_BRANDS } from './graphql/queries';
import { Brand } from './brand.model';
import { CREATE_BRAND, DELETE_BRAND, UPDATE_BRAND } from './graphql/mutations';
@Injectable()
export class BrandService {
constructor(private readonly apollo: Apollo) {}
listBrands(): Observable<any> {
return this.apollo
.watchQuery<Brand>({
query: LIST_BRANDS(),
})
.valueChanges
}
findUniqueBrand(id: Brand["id"]): Observable<any> {
return this.apollo
.watchQuery<Brand>({
query: FIND_UNIQUE_BRAND(id),
})
.valueChanges
}
createBrand(category: Brand) {
return this.apollo
.mutate<any>({
mutation: CREATE_BRAND(category),
});
}
updateBrand(category: Brand) {
return this.apollo
.mutate({
mutation: UPDATE_BRAND(category),
});
}
deleteBrand(id: string) {
return this.apollo
.mutate({
mutation: DELETE_BRAND(id),
});
}
}

View file

@ -0,0 +1,47 @@
import { gql } from "apollo-angular";
import { Brand } from "../brand.model";
export const UPDATE_BRAND = (brand: Brand) => gql`
mutation UpdateBrand {
updateBrand(
data: {
name: { set: "${brand.name}" }
},
where: {
id: "${brand.id}"
}) {
createdAt
id
name
updatedAt
_count {
products
}
}
}
`;
export const CREATE_BRAND = (brand: Brand) => gql`
mutation CreateBrand {
createBrand(data: { name: "${brand.name}" }) {
createdAt
id
name
updatedAt
_count {
products
}
}
}
`;
export const DELETE_BRAND = (id: string) => gql`
mutation DeleteBrand {
deleteBrand(where: { id: "${id}" }) {
createdAt
id
name
updatedAt
}
}
`;

View file

@ -0,0 +1,27 @@
import { gql } from "apollo-angular";
export const LIST_BRANDS = () => gql`
query ListBrands {
listBrands {
createdAt
id
name
updatedAt
}
}
`;
export const FIND_UNIQUE_BRAND = (id: string) =>
gql`
query FindUniqueBrand {
findUniqueBrand(where: { id: "${id}" }) {
createdAt
id
name
updatedAt
_count {
products
}
}
}
`;

View file

@ -0,0 +1,9 @@
export class CategoryCount {
Product?: number;
SubCategory?: number;
constructor(){
this.Product = 0;
this.SubCategory = 0;
}
}

View file

@ -0,0 +1,10 @@
<nb-card>
<nb-card-header>
Categories
</nb-card-header>
<nb-card-body>
<ng2-smart-table [settings]="settings" [source]="source" (edit)="onEdit($event)" (userRowSelect)="onEdit($event)">
</ng2-smart-table>
</nb-card-body>
</nb-card>

View file

@ -0,0 +1,7 @@
@import '../../../@theme/styles/themes';
@include nb-install-component() {
nb-card {
transform: translate3d(0, 0, 0);
}
}

View file

@ -0,0 +1,70 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { LocalDataSource } from "ng2-smart-table";
import { CategoryService } from "../category.service";
import { Router } from "@angular/router";
import { Category } from "../category.model";
import { Subject } from "rxjs";
import { takeUntil, tap } from "rxjs/operators";
@Component({
selector: "ngx-category-edit",
templateUrl: "./category-edit.component.html",
styleUrls: ["./category-edit.component.scss"],
})
export class CategoryEditComponent implements OnInit, OnDestroy {
private destroy$: Subject<void> = new Subject<void>();
settings = {
mode: 'external',
actions: {
add: false,
delete: false,
},
edit: {
editButtonContent: '<i class="nb-edit"></i>',
saveButtonContent: '<i class="nb-checkmark"></i>',
cancelButtonContent: '<i class="nb-close"></i>',
},
columns: {
id: {
title: "ID",
type: "string",
editable: false,
},
name: {
title: "Name",
type: "string",
editable: false,
}
},
};
source: LocalDataSource = new LocalDataSource();
loading: boolean = true;
categories: Category[];
constructor(private categoryService: CategoryService, private router: Router) {}
ngOnInit(): void {
this.categoryService.listCategories()
.pipe(
tap(() => {
this.loading = true;
}),
takeUntil(this.destroy$)
).subscribe(({ data, loading }) => {
this.loading = loading;
this.categories = data.listCategorys;
this.source.load(this.categories);
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
onEdit(event): void {
this.router.navigate(["admin", "category", "edit", event.data.id]);
}
}

View file

@ -0,0 +1,37 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { CategoryComponent } from './category.component';
import { CategoryEditComponent } from './category-edit/category-edit.component';
import { CategoryUpsertComponent } from './category-upsert/category-upsert.component';
const routes: Routes = [{
path: '',
component: CategoryComponent,
children: [
{
path: 'edit',
component: CategoryEditComponent,
},
{
path: 'edit/:id',
component: CategoryUpsertComponent,
},
{
path: 'create',
component: CategoryUpsertComponent,
},
],
}];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class CategoryRoutingModule { }
export const routedComponents = [
CategoryComponent,
CategoryEditComponent,
CategoryUpsertComponent
];

View file

@ -0,0 +1,69 @@
<div class="row">
<div class="col-md-12">
<nb-card *ngIf="!loading">
<nb-card-header>
<nb-icon (click)="goBackToList()" [icon]="'arrow-ios-back-outline'" pack="eva"></nb-icon>
Category {{ category.id }}</nb-card-header>
<nb-card-body>
<div *ngIf="category.id" class="summary-container">
<div>
<div>Created At</div>
<div class="h6">{{ category.createdAt | date: 'dd:MM:YYYY HH:mm:ss' }}</div>
</div>
<div>
<div>Sub Categories Count</div>
<div class="h6">{{ category._count?.SubCategory || 0 }}</div>
</div>
<div>
<div>Products Count</div>
<div class="h6">{{ category._count?.Product || 0 }}</div>
</div>
</div>
<form (ngSubmit)="onSubmit(categoryForm.form)" #categoryForm="ngForm">
<div class="form-group">
<label for="categoryName" class="label">Name</label>
<input
type="text"
nbInput
fullWidth
id="categoryName"
placeholder="Name"
required
[(ngModel)]="category.name"
name="name"
/>
</div>
<div *ngIf="category.id" class="row">
<div class="col-md-12 col-lg-12 col-xxxl-12">
<nb-card class="list-card" size="small">
<nb-card-header>Sub Categories</nb-card-header>
<nb-card-body *ngIf="category.SubCategory.length === 0">
No sub categories yet.
</nb-card-body>
<nb-list *ngIf="category.SubCategory.length > 0">
<nb-list-item *ngFor="let subCategory of category.SubCategory; let i = index;">
{{subCategory.name}}
</nb-list-item>
</nb-list>
</nb-card>
</div>
</div>
<div class="form-group ">
<button
type="submit"
nbButton
status="primary"
[disabled]="!categoryForm.form.valid"
>
Submit
</button>
</div>
</form>
</nb-card-body>
</nb-card>
</div>
</div>

View file

@ -0,0 +1,35 @@
@import '../../../@theme/styles/themes';
nb-checkbox {
margin-bottom: 1rem;
}
nb-icon {
cursor: pointer;
}
.form-inline [fullWidth] {
flex: 1;
}
.form-inline > * {
margin: 0 1.5rem 1.5rem 0;
}
nb-card.inline-form-card nb-card-body {
padding-bottom: 0;
}
@include nb-install-component() {
.summary-container {
display: flex;
flex-wrap: wrap;
flex: 1;
background-color: nb-theme(background-basic-color-2);
justify-content: space-between;
padding: 1.5rem 4rem 1rem;
border: 1px solid nb-theme(border-basic-color-3);
border-left: none;
border-right: none;
}
}

View file

@ -0,0 +1,125 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute, ParamMap, Router } from "@angular/router";
import { CategoryService } from "../category.service";
import { Category } from "../category.model";
import { NgForm } from "@angular/forms";
import { takeUntil, tap } from "rxjs/operators";
import {
NbToastrService,
} from "@nebular/theme";
import { Subject } from "rxjs";
import { SubCategory } from "../../sub-category/sub-category.model";
@Component({
selector: "ngx-category-upsert",
styleUrls: ["./category-upsert.component.scss"],
templateUrl: "./category-upsert.component.html",
})
export class CategoryUpsertComponent implements OnInit, OnDestroy {
private destroy$: Subject<void> = new Subject<void>();
id: string;
loading: boolean = false;
category: Category;
subCategories: SubCategory[] = [];
constructor(
private route: ActivatedRoute,
private router: Router,
private toastrService: NbToastrService,
private categoryService: CategoryService
) {
this.category = new Category();
}
ngOnInit(): void {
this.route.paramMap.subscribe((params: ParamMap) => {
this.id = params.get("id");
if (this.id) {
this.categoryService
.findUniqueCategory(this.id)
.pipe(
tap(() => {
this.loading = true;
}),
takeUntil(this.destroy$)
)
.subscribe(({ data, loading }) => {
this.loading = loading;
this.category = Object.assign({}, data.findUniqueCategory);
this.category.SubCategory = [...data.findUniqueCategory.SubCategory]
});
}
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
onSubmit(form: NgForm) {
const category = {
...form.value,
id: this.id
} as Category;
if (this.id) {
this.categoryService
.updateCategory(category)
.pipe(takeUntil(this.destroy$))
.subscribe(
({ data }) => {
this.toastrService.show(
null,
`Category has been successfully updated`,
{
status: "success",
}
);
},
(error) => {
this.toastrService.show(error.toString(), `Something went wrong`, {
status: "danger",
});
}
);
} else {
this.categoryService
.createCategory(category)
.pipe(takeUntil(this.destroy$))
.subscribe(
({ data }) => {
this.toastrService.show(
null,
`Category has been successfully created`,
{
status: "success",
}
);
this.router.navigate([
"admin",
"category",
"edit",
data.createCategory.id,
]);
},
(error) => {
this.toastrService.show(error.toString(), `Something went wrong`, {
status: "danger",
});
}
);
}
}
goBackToList() {
this.router.navigate([
"admin",
"category",
"edit"
]);
}
}

View file

@ -0,0 +1,8 @@
import { Component } from '@angular/core';
@Component({
selector: 'ngx-category',
template: `<router-outlet></router-outlet>`,
})
export class CategoryComponent {
}

View file

@ -0,0 +1,16 @@
import { CategoryCount } from "./category-count.model";
export class Category {
id!: string;
name!: string;
createdAt!: Date;
updatedAt!: Date | null;
//Products?: Array<Product>;
SubCategory?: Array<any>; //TODO:
_count?: CategoryCount;
constructor() {
this.SubCategory = [];
this._count = new CategoryCount();
}
}

View file

@ -0,0 +1,49 @@
import { NgModule } from '@angular/core';
import {
NbActionsModule,
NbButtonModule,
NbCardModule,
NbCheckboxModule,
NbDatepickerModule,
NbIconModule,
NbInputModule,
NbRadioModule,
NbSelectModule,
NbUserModule,
NbTreeGridModule,
NbListModule
} from '@nebular/theme';
import { Ng2SmartTableModule } from 'ng2-smart-table';
import { ThemeModule } from '../../@theme/theme.module';
import { CategoryRoutingModule, routedComponents } from './category-routing.module';
import { CategoryService } from './category.service';
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [
NbCardModule,
NbTreeGridModule,
NbIconModule,
NbInputModule,
ThemeModule,
CategoryRoutingModule,
Ng2SmartTableModule,
FormsModule,
NbButtonModule,
NbActionsModule,
NbUserModule,
NbCheckboxModule,
NbRadioModule,
NbDatepickerModule,
NbSelectModule,
NbListModule
],
declarations: [
...routedComponents
],
providers: [
CategoryService,
],
})
export class CategoryModule { }

View file

@ -0,0 +1,44 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Apollo } from 'apollo-angular';
import { FIND_UNIQUE_CATEGORY, LIST_CATEGORIES } from './graphql/queries';
import { Category } from './category.model';
import { CREATE_CATEGORY, UPDATE_CATEGORY } from './graphql/mutations';
@Injectable()
export class CategoryService {
constructor(private readonly apollo: Apollo) {}
listCategories(): Observable<any> {
return this.apollo
.watchQuery<Category>({
query: LIST_CATEGORIES(),
})
.valueChanges
}
findUniqueCategory(id: Category["id"]): Observable<any> {
return this.apollo
.watchQuery<Category>({
query: FIND_UNIQUE_CATEGORY(id),
})
.valueChanges
}
createCategory(category: Category) {
console.log(CREATE_CATEGORY(category));
return this.apollo
.mutate<any>({
mutation: CREATE_CATEGORY(category),
});
}
updateCategory(category: Category) {
console.log(UPDATE_CATEGORY(category));
return this.apollo
.mutate({
mutation: UPDATE_CATEGORY(category),
});
}
}

View file

@ -0,0 +1,50 @@
import { gql } from "apollo-angular";
import { Category } from "../category.model";
export const UPDATE_CATEGORY = (category: Category) => gql`
mutation UpdateCategory {
updateCategory(
data: {
name: { set: "${category.name}" }
},
where: {
id: "${category.id}"
}) {
createdAt
id
name
updatedAt
SubCategory {
id
name
}
_count {
Product
SubCategory
}
}
}
`;
const buildSubCategoryWhere = (id: string) => {
return `{ id: "${id}" }`;
}
export const CREATE_CATEGORY = (category: Category) => gql`
mutation CreateCategory {
createCategory(data: { name: "${category.name}" }) {
createdAt
id
name
updatedAt
SubCategory {
id
name
}
_count {
Product
SubCategory
}
}
}
`;

View file

@ -0,0 +1,36 @@
import { gql } from "apollo-angular";
export const LIST_CATEGORIES = () => gql`
query ListCategorys {
listCategorys {
createdAt
id
name
updatedAt
SubCategory {
id
name
}
}
}
`;
export const FIND_UNIQUE_CATEGORY = (id: string) =>
gql`
query FindUniqueCategory {
findUniqueCategory(where: { id: "${id}" }) {
createdAt
id
name
updatedAt
SubCategory {
id
name
}
_count {
Product
SubCategory
}
}
}
`;

View file

@ -0,0 +1,7 @@
export class ChatCount {
messages?: number;
constructor(){
this.messages = 0;
}
}

View file

@ -0,0 +1,10 @@
<nb-card>
<nb-card-header>
Categories
</nb-card-header>
<nb-card-body>
<ng2-smart-table [settings]="settings" [source]="source" (edit)="onEdit($event)" (userRowSelect)="onEdit($event)">
</ng2-smart-table>
</nb-card-body>
</nb-card>

View file

@ -0,0 +1,7 @@
@import '../../../@theme/styles/themes';
@include nb-install-component() {
nb-card {
transform: translate3d(0, 0, 0);
}
}

View file

@ -0,0 +1,71 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { LocalDataSource } from "ng2-smart-table";
import { ChatService } from "../chat.service";
import { Router } from "@angular/router";
import { Chat } from "../chat.model";
import { Subject } from "rxjs";
import { takeUntil, tap } from "rxjs/operators";
@Component({
selector: "ngx-chat-messages",
templateUrl: "./chat-messages.component.html",
styleUrls: ["./chat-messages.component.scss"],
})
export class ChatMessageComponent implements OnInit, OnDestroy {
private destroy$: Subject<void> = new Subject<void>();
settings = {
mode: 'external',
actions: {
add: false,
delete: false,
},
edit: {
editButtonContent: '<i class="nb-edit"></i>',
saveButtonContent: '<i class="nb-checkmark"></i>',
cancelButtonContent: '<i class="nb-close"></i>',
},
columns: {
id: {
title: "ID",
type: "string",
editable: false,
},
name: {
title: "Name",
type: "string",
editable: false,
}
},
};
source: LocalDataSource = new LocalDataSource();
loading: boolean = true;
brands: Chat[];
constructor(private brandService: ChatService, private router: Router) {
}
ngOnInit(): void {
this.brandService.listChats()
.pipe(
tap(() => {
this.loading = true;
}),
takeUntil(this.destroy$)
).subscribe(({ data, loading }) => {
this.loading = loading;
this.brands = data.listChats;
this.source.load(this.brands);
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
onEdit(event): void {
this.router.navigate(["admin", "brand", "edit", event.data.id]);
}
}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ChatComponent } from './chat/chat.component';
import { ChatMessageComponent } from './chat-messages/chat-messages.component';
const routes: Routes = [{
path: '',
component: ChatComponent
}];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class ChatRoutingModule { }
export const routedComponents = [
ChatComponent,
ChatMessageComponent
];

View file

@ -0,0 +1,16 @@
import { ChatCount } from "./chat-count.model";
import { Message } from "./message.model";
import { User } from "./user.model";
export class Chat {
id!: string;
userFromId!: string;
userToId!: string;
createdAt!: Date;
isActive!: boolean;
userFrom?: User;
userTo?: User;
messages?: Array<Message>;
//review?: Review | null;
_count?: ChatCount;
}

View file

@ -0,0 +1,49 @@
import { NgModule } from '@angular/core';
import {
NbActionsModule,
NbButtonModule,
NbCardModule,
NbCheckboxModule,
NbDatepickerModule,
NbIconModule,
NbInputModule,
NbRadioModule,
NbSelectModule,
NbUserModule,
NbTreeGridModule,
NbListModule
} from '@nebular/theme';
import { Ng2SmartTableModule } from 'ng2-smart-table';
import { ThemeModule } from '../../@theme/theme.module';
import { ChatRoutingModule, routedComponents } from './chat-routing.module';
import { ChatService } from './chat.service';
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [
NbCardModule,
NbTreeGridModule,
NbIconModule,
NbInputModule,
ThemeModule,
ChatRoutingModule,
Ng2SmartTableModule,
FormsModule,
NbButtonModule,
NbActionsModule,
NbUserModule,
NbCheckboxModule,
NbRadioModule,
NbDatepickerModule,
NbSelectModule,
NbListModule
],
declarations: [
...routedComponents
],
providers: [
ChatService,
],
})
export class ChatModule { }

View file

@ -0,0 +1,36 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Apollo } from 'apollo-angular';
import { FIND_UNIQUE_CHAT, LIST_CHATS } from './graphql/queries';
import { Chat } from './chat.model';
import { CREATE_CHAT } from './graphql/mutations';
@Injectable()
export class ChatService {
constructor(private readonly apollo: Apollo) {}
listChats(): Observable<any> {
return this.apollo
.watchQuery<Chat>({
query: LIST_CHATS(),
})
.valueChanges
}
findUniqueChat(id: Chat["id"]): Observable<any> {
return this.apollo
.watchQuery<Chat>({
query: FIND_UNIQUE_CHAT(id),
})
.valueChanges
}
createChat(category: Chat) {
return this.apollo
.mutate<any>({
mutation: CREATE_CHAT(category),
});
}
}

View file

@ -0,0 +1,58 @@
<div class="row">
<div class="col-md-12">
<nb-card *ngIf="!loading">
<nb-card-header>
<nb-icon (click)="goBackToList()" [icon]="'arrow-ios-back-outline'" pack="eva"></nb-icon>
Brand {{ brand.id }}</nb-card-header>
<nb-card-body>
<div *ngIf="brand.id" class="summary-container">
<div>
<div>Created At</div>
<div class="h6">{{ brand.createdAt | date: 'dd:MM:YYYY HH:mm:ss' }}</div>
</div>
<div>
<div>Products Count</div>
<div class="h6">{{ brand._count?.products || 0 }}</div>
</div>
</div>
<form (ngSubmit)="onSubmit(brandForm.form)" #brandForm="ngForm">
<div class="form-group">
<label for="brandName" class="label">Name</label>
<input
type="text"
nbInput
fullWidth
id="brandName"
placeholder="Name"
required
[(ngModel)]="brand.name"
name="name"
/>
</div>
<div class="form-group buttons-row">
<button
type="submit"
nbButton
status="primary"
[disabled]="!brandForm.form.valid"
>
Submit
</button>
<button
*ngIf="brand.id"
type="button"
(click)="onDelete()"
nbButton
status="danger"
>
Delete
</button>
</div>
</form>
</nb-card-body>
</nb-card>
</div>
</div>

View file

@ -0,0 +1,43 @@
@import "../../../@theme/styles/themes";
nb-checkbox {
margin-bottom: 1rem;
}
nb-icon {
cursor: pointer;
}
.form-inline [fullWidth] {
flex: 1;
}
.form-inline > * {
margin: 0 1.5rem 1.5rem 0;
}
nb-card.inline-form-card nb-card-body {
padding-bottom: 0;
}
@include nb-install-component() {
.summary-container {
display: flex;
flex-wrap: wrap;
flex: 1;
background-color: nb-theme(background-basic-color-2);
justify-content: space-between;
padding: 1.5rem 4rem 1rem;
border: 1px solid nb-theme(border-basic-color-3);
border-left: none;
border-right: none;
}
.buttons-row {
margin: -0.5rem;
}
button[nbButton] {
margin: 0.5rem;
}
}

View file

@ -0,0 +1,32 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ChatService } from "../chat.service";
import { Chat } from "../chat.model";
import { Subject } from "rxjs";
@Component({
selector: "ngx-chat",
styleUrls: ["./chat.component.scss"],
templateUrl: "./chat.component.html",
})
export class ChatComponent implements OnInit, OnDestroy {
private destroy$: Subject<void> = new Subject<void>();
id: string;
loading: boolean = false;
chat: Chat;
constructor(
private chatService: ChatService
) {
this.chat = new Chat();
}
ngOnInit(): void {
console.log('init')
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}

View file

@ -0,0 +1,47 @@
import { gql } from "apollo-angular";
import { Chat } from "../chat.model";
export const UPDATE_CHAT = (chat: Chat) => gql`
mutation UpdateChat {
updateChat(
data: {
name: { set: "${chat.id}" }
},
where: {
id: "${chat.id}"
}) {
createdAt
id
name
updatedAt
_count {
products
}
}
}
`;
export const CREATE_CHAT = (chat: Chat) => gql`
mutation CreateChat {
createChat(data: { name: "${chat.id}" }) {
createdAt
id
name
updatedAt
_count {
products
}
}
}
`;
export const DELETE_CHAT = (id: string) => gql`
mutation DeleteChat {
deleteChat(where: { id: "${id}" }) {
createdAt
id
name
updatedAt
}
}
`;

View file

@ -0,0 +1,27 @@
import { gql } from "apollo-angular";
export const LIST_CHATS = () => gql`
query ListBrands {
listBrands {
createdAt
id
name
updatedAt
}
}
`;
export const FIND_UNIQUE_CHAT = (id: string) =>
gql`
query FindUniqueBrand {
findUniqueBrand(where: { id: "${id}" }) {
createdAt
id
name
updatedAt
_count {
products
}
}
}
`;

View file

@ -0,0 +1,14 @@
import { Chat } from "./chat.model";
import { User } from "./user.model";
export class Message {
id!: string;
userId!: string;
chatId!: string;
text!: string;
imgUrl!: string | null;
createdAt!: Date;
isRead!: boolean;
user?: User;
chat?: Chat;
}

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