WIP
This commit is contained in:
parent
42e7ee39be
commit
6301d6008b
@ -10,7 +10,7 @@ import {
|
|||||||
LayoutService,
|
LayoutService,
|
||||||
PlayerService,
|
PlayerService,
|
||||||
SeoService,
|
SeoService,
|
||||||
StateService,
|
StateServiceForNB,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import { UserData } from './data/users';
|
import { UserData } from './data/users';
|
||||||
import { ElectricityData } from './data/electricity';
|
import { ElectricityData } from './data/electricity';
|
||||||
@ -142,7 +142,7 @@ export const NB_CORE_PROVIDERS = [
|
|||||||
LayoutService,
|
LayoutService,
|
||||||
PlayerService,
|
PlayerService,
|
||||||
SeoService,
|
SeoService,
|
||||||
StateService,
|
StateServiceForNB,
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { LayoutService } from './layout.service';
|
import { LayoutService } from './layout.service';
|
||||||
import { AnalyticsService } from './analytics.service';
|
import { AnalyticsService } from './analytics.service';
|
||||||
import { PlayerService } from './player.service';
|
import { PlayerService } from './player.service';
|
||||||
import { StateService } from './state.service';
|
import { StateServiceForNB } from './state.service';
|
||||||
import { SeoService } from './seo.service';
|
import { SeoService } from './seo.service';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@ -9,5 +9,5 @@ export {
|
|||||||
AnalyticsService,
|
AnalyticsService,
|
||||||
PlayerService,
|
PlayerService,
|
||||||
SeoService,
|
SeoService,
|
||||||
StateService,
|
StateServiceForNB,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { takeWhile } from 'rxjs/operators';
|
|||||||
import { NbLayoutDirectionService, NbLayoutDirection } from '@nebular/theme';
|
import { NbLayoutDirectionService, NbLayoutDirection } from '@nebular/theme';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class StateService implements OnDestroy {
|
export class StateServiceForNB implements OnDestroy {
|
||||||
|
|
||||||
protected layouts: any = [
|
protected layouts: any = [
|
||||||
{
|
{
|
||||||
@ -58,7 +58,7 @@ export class StateService implements OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateSidebarIcons(direction: NbLayoutDirection) {
|
private updateSidebarIcons(direction: NbLayoutDirection) {
|
||||||
const [ startSidebar, endSidebar ] = this.sidebars;
|
const [startSidebar, endSidebar] = this.sidebars;
|
||||||
const isLtr = direction === NbLayoutDirection.LTR;
|
const isLtr = direction === NbLayoutDirection.LTR;
|
||||||
const startIconClass = isLtr ? 'nb-layout-sidebar-left' : 'nb-layout-sidebar-right';
|
const startIconClass = isLtr ? 'nb-layout-sidebar-left' : 'nb-layout-sidebar-right';
|
||||||
const endIconClass = isLtr ? 'nb-layout-sidebar-right' : 'nb-layout-sidebar-left';
|
const endIconClass = isLtr ? 'nb-layout-sidebar-right' : 'nb-layout-sidebar-left';
|
||||||
|
|||||||
34
src/app/@theme/components/header/breakPoint.ts
Normal file
34
src/app/@theme/components/header/breakPoint.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
export const DEFAULT_MEDIA_BREAKPOINTS = [
|
||||||
|
{
|
||||||
|
name: 'xs',
|
||||||
|
width: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'is',
|
||||||
|
width: 400,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sm',
|
||||||
|
width: 576,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'md',
|
||||||
|
width: 768,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'lg',
|
||||||
|
width: 992,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'xl',
|
||||||
|
width: 1200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'xxl',
|
||||||
|
width: 1400,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'xxxl',
|
||||||
|
width: 1600,
|
||||||
|
},
|
||||||
|
];
|
||||||
@ -9,6 +9,7 @@ import { HeaderService } from '../../../services/header.service';
|
|||||||
import { NbAuthService } from '@nebular/auth';
|
import { NbAuthService } from '@nebular/auth';
|
||||||
import { AuthService } from '../../../services/auth.service';
|
import { AuthService } from '../../../services/auth.service';
|
||||||
import { UserProfileAction } from '../../../entity/Auth';
|
import { UserProfileAction } from '../../../entity/Auth';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ngx-header',
|
selector: 'ngx-header',
|
||||||
@ -19,6 +20,7 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||||||
header: string = '';
|
header: string = '';
|
||||||
private destroy$: Subject<void> = new Subject<void>();
|
private destroy$: Subject<void> = new Subject<void>();
|
||||||
userPictureOnly: boolean = false;
|
userPictureOnly: boolean = false;
|
||||||
|
isLessThanMd: boolean = false;
|
||||||
|
|
||||||
themes = [
|
themes = [
|
||||||
{
|
{
|
||||||
@ -68,7 +70,8 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
constructor(private sidebarService: NbSidebarService,
|
constructor(
|
||||||
|
private sidebarService: NbSidebarService,
|
||||||
private menuService: NbMenuService,
|
private menuService: NbMenuService,
|
||||||
private themeService: NbThemeService,
|
private themeService: NbThemeService,
|
||||||
private userService: UserData,
|
private userService: UserData,
|
||||||
@ -77,15 +80,12 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||||||
private headerService: HeaderService,
|
private headerService: HeaderService,
|
||||||
private oAuthService: NbAuthService,
|
private oAuthService: NbAuthService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
|
protected router: Router,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
this.headerService.headerChange$.pipe(takeUntil(this.destroy$)).subscribe(result => {
|
this.headerService.headerChange$.pipe(takeUntil(this.destroy$)).subscribe(result => {
|
||||||
this.header = result;
|
this.header = result;
|
||||||
});
|
});
|
||||||
this.menuService.onItemClick().pipe(takeUntil(this.destroy$))
|
|
||||||
.subscribe(result => {
|
|
||||||
if (result.item.title == 'Log out') this.logout();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -93,13 +93,18 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.currentTheme = this.themeService.currentTheme;
|
this.currentTheme = this.themeService.currentTheme;
|
||||||
|
|
||||||
const { xl } = this.breakpointService.getBreakpointsMap();
|
const { md, xl } = this.breakpointService.getBreakpointsMap();
|
||||||
this.themeService.onMediaQueryChange()
|
this.themeService.onMediaQueryChange()
|
||||||
.pipe(
|
.pipe(
|
||||||
map(([, currentBreakpoint]) => currentBreakpoint.width < xl),
|
map(([, currentBreakpoint]) => currentBreakpoint.width),
|
||||||
takeUntil(this.destroy$),
|
takeUntil(this.destroy$),
|
||||||
)
|
)
|
||||||
.subscribe((isLessThanXl: boolean) => this.userPictureOnly = isLessThanXl);
|
.subscribe((screenWidth: number) => {
|
||||||
|
let isLessThanXl = screenWidth < xl;
|
||||||
|
this.isLessThanMd = screenWidth < md;
|
||||||
|
this.userPictureOnly = isLessThanXl
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
this.themeService.onThemeChange()
|
this.themeService.onThemeChange()
|
||||||
.pipe(
|
.pipe(
|
||||||
@ -108,6 +113,22 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||||||
)
|
)
|
||||||
.subscribe(themeName => this.currentTheme = themeName);
|
.subscribe(themeName => this.currentTheme = themeName);
|
||||||
|
|
||||||
|
this.menuService.onItemClick().subscribe(result => {
|
||||||
|
if (this.isLessThanMd && result.tag == 'NavMenu' && result.item.link) {
|
||||||
|
this.toggleSidebar();
|
||||||
|
} else if (result.tag == 'UserProfileMenu') {
|
||||||
|
switch (result.item.data as UserProfileAction) {
|
||||||
|
case UserProfileAction.None: break;
|
||||||
|
case UserProfileAction.GoToProfile:
|
||||||
|
this.router.navigate(["/myapp/profile"]);
|
||||||
|
break;
|
||||||
|
case UserProfileAction.LogOut:
|
||||||
|
this.logout();
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<ngx-one-column-layout>
|
<ngx-one-column-layout>
|
||||||
<nb-menu [items]="MENU_ITEMS"></nb-menu>
|
<nb-menu [items]="MENU_ITEMS" tag="NavMenu"></nb-menu>
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</ngx-one-column-layout>
|
</ngx-one-column-layout>
|
||||||
@ -6,10 +6,7 @@ import { AdminComponent } from './admin.component';
|
|||||||
import { NbMenuModule, NbInputModule, NbCardModule, NbButtonModule, NbActionsModule, NbCheckboxModule, NbRadioModule, NbDatepickerModule, NbSelectModule, NbIconModule, NbTagModule, NbStepperModule, NbListModule, NbSpinnerModule, NbDialogModule, NbUserModule } from '@nebular/theme';
|
import { NbMenuModule, NbInputModule, NbCardModule, NbButtonModule, NbActionsModule, NbCheckboxModule, NbRadioModule, NbDatepickerModule, NbSelectModule, NbIconModule, NbTagModule, NbStepperModule, NbListModule, NbSpinnerModule, NbDialogModule, NbUserModule } from '@nebular/theme';
|
||||||
import { ThemeModule } from '../@theme/theme.module';
|
import { ThemeModule } from '../@theme/theme.module';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { BestListDlgComponent } from './happiness-groups/best-list-dlg/best-list-dlg.component';
|
|
||||||
import { AlertDlgModule } from '../ui/alert-dlg/alert-dlg.module';
|
import { AlertDlgModule } from '../ui/alert-dlg/alert-dlg.module';
|
||||||
import { HappinessWeekEditorComponent } from './happiness-groups/happiness-week-editor/happiness-week-editor.component';
|
|
||||||
import { HappinessWeekListDlgComponent } from './happiness-groups/happiness-week-list-dlg/happiness-week-list-dlg.component';
|
|
||||||
import { CellGroupRoutineEventsComponent } from './cell-group-routine-events/cell-group-routine-events.component';
|
import { CellGroupRoutineEventsComponent } from './cell-group-routine-events/cell-group-routine-events.component';
|
||||||
import { FancyTableModule } from '../ui/fancy-table/fancy-table.module';
|
import { FancyTableModule } from '../ui/fancy-table/fancy-table.module';
|
||||||
import { FamilyMembersComponent } from './family-members/family-members.component';
|
import { FamilyMembersComponent } from './family-members/family-members.component';
|
||||||
@ -26,14 +23,9 @@ import { MaskDirectiveModule } from '../directives/mask-directive/mask-directive
|
|||||||
import { DateInputModule } from '../ui/date-input/date-input.module';
|
import { DateInputModule } from '../ui/date-input/date-input.module';
|
||||||
import { LineMessagingAccountComponent } from './lines/line-messaging-account/line-messaging-account.component';
|
import { LineMessagingAccountComponent } from './lines/line-messaging-account/line-messaging-account.component';
|
||||||
import { LineMessagingAccountEditorComponent } from './lines/line-messaging-account-editor/line-messaging-account-editor.component';
|
import { LineMessagingAccountEditorComponent } from './lines/line-messaging-account-editor/line-messaging-account-editor.component';
|
||||||
import { WeekTaskEditorComponent } from './happiness-groups/week-task-editor/week-task-editor.component';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AdminComponent,
|
AdminComponent,
|
||||||
BestListDlgComponent,
|
|
||||||
HappinessWeekEditorComponent,
|
|
||||||
HappinessWeekListDlgComponent,
|
|
||||||
CellGroupRoutineEventsComponent,
|
CellGroupRoutineEventsComponent,
|
||||||
FamilyMembersComponent,
|
FamilyMembersComponent,
|
||||||
FamilyMemberEditorComponent,
|
FamilyMemberEditorComponent,
|
||||||
@ -44,7 +36,7 @@ import { WeekTaskEditorComponent } from './happiness-groups/week-task-editor/wee
|
|||||||
LogDetailComponent,
|
LogDetailComponent,
|
||||||
LineMessagingAccountComponent,
|
LineMessagingAccountComponent,
|
||||||
LineMessagingAccountEditorComponent,
|
LineMessagingAccountEditorComponent,
|
||||||
WeekTaskEditorComponent],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
|
|||||||
@ -4,10 +4,10 @@ import { NbDialogService } from '@nebular/theme';
|
|||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from 'rxjs/operators';
|
||||||
import { inherits } from 'util';
|
import { inherits } from 'util';
|
||||||
import { StateService } from '../../@core/utils';
|
|
||||||
import { CellGroupRoutineEvents } from '../../entity/CellGroupRoutineEvents';
|
import { CellGroupRoutineEvents } from '../../entity/CellGroupRoutineEvents';
|
||||||
import { CellGroupRoutineEventsService } from '../../services/crudServices/cell-group-routine-events.service';
|
import { CellGroupRoutineEventsService } from '../../services/crudServices/cell-group-routine-events.service';
|
||||||
import { MsgBoxService } from '../../services/msg-box.service';
|
import { MsgBoxService } from '../../services/msg-box.service';
|
||||||
|
import { StateService } from '../../services/state.service';
|
||||||
import { FancySettings } from '../../ui/fancy-table/fancy-settings.model';
|
import { FancySettings } from '../../ui/fancy-table/fancy-settings.model';
|
||||||
import { FancyTableComponent } from '../../ui/fancy-table/fancy-table.component';
|
import { FancyTableComponent } from '../../ui/fancy-table/fancy-table.component';
|
||||||
import { ObjectUtils } from '../../utilities/object-utils';
|
import { ObjectUtils } from '../../utilities/object-utils';
|
||||||
|
|||||||
@ -3,10 +3,10 @@ import { NbDialogRef } from '@nebular/theme';
|
|||||||
import { DropDownOption } from '../../../entity/dropDownOption';
|
import { DropDownOption } from '../../../entity/dropDownOption';
|
||||||
import { DomainMemberRelationship, PastoralDomain } from '../../../entity/PastoralDomain';
|
import { DomainMemberRelationship, PastoralDomain } from '../../../entity/PastoralDomain';
|
||||||
import { DialogComponent } from '../../../pages/modal-overlays/dialog/dialog.component';
|
import { DialogComponent } from '../../../pages/modal-overlays/dialog/dialog.component';
|
||||||
import { DomainMemberShipService } from '../../../services/crudServices/pastoral-domain.service';
|
|
||||||
import { ArrayUtils } from '../../../utilities/array-utils';
|
import { ArrayUtils } from '../../../utilities/array-utils';
|
||||||
import { first } from "rxjs/operators"
|
import { first } from "rxjs/operators"
|
||||||
import { FamilyMember } from '../../../entity/Member';
|
import { FamilyMember } from '../../../entity/Member';
|
||||||
|
import { DomainMemberShipService } from '../../../services/crudServices/domain-member-ship.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ngx-assign-member-cell-group',
|
selector: 'ngx-assign-member-cell-group',
|
||||||
|
|||||||
@ -3,12 +3,12 @@ import { ActivatedRoute } from '@angular/router';
|
|||||||
import { NbDialogService } from '@nebular/theme';
|
import { NbDialogService } from '@nebular/theme';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from 'rxjs/operators';
|
||||||
import { StateService } from '../../@core/utils';
|
|
||||||
import { FamilyMember, Gender } from '../../entity/Member';
|
import { FamilyMember, Gender } from '../../entity/Member';
|
||||||
import { PastoralDomain } from '../../entity/PastoralDomain';
|
import { PastoralDomain } from '../../entity/PastoralDomain';
|
||||||
import { FamilyMemberService } from '../../services/crudServices/family-member.service';
|
import { FamilyMemberService } from '../../services/crudServices/family-member.service';
|
||||||
import { PastoralDomainService } from '../../services/crudServices/pastoral-domain.service';
|
import { PastoralDomainService } from '../../services/crudServices/pastoral-domain.service';
|
||||||
import { MsgBoxService } from '../../services/msg-box.service';
|
import { MsgBoxService } from '../../services/msg-box.service';
|
||||||
|
import { StateService } from '../../services/state.service';
|
||||||
import { FancySettings } from '../../ui/fancy-table/fancy-settings.model';
|
import { FancySettings } from '../../ui/fancy-table/fancy-settings.model';
|
||||||
import { FancyTableComponent } from '../../ui/fancy-table/fancy-table.component';
|
import { FancyTableComponent } from '../../ui/fancy-table/fancy-table.component';
|
||||||
import { ObjectUtils } from '../../utilities/object-utils';
|
import { ObjectUtils } from '../../utilities/object-utils';
|
||||||
|
|||||||
@ -1,4 +0,0 @@
|
|||||||
nb-card {
|
|
||||||
max-height: 90vh;
|
|
||||||
width: 700px;
|
|
||||||
}
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import { NbDialogRef, NbToastrService } from '@nebular/theme';
|
|
||||||
import { first } from 'rxjs/operators';
|
|
||||||
import { environment } from '../../../../environments/environment';
|
|
||||||
import { HappinessBEST } from '../../../entity/HappinessGroup';
|
|
||||||
import { PastoralDomain } from '../../../entity/PastoralDomain';
|
|
||||||
import { BestService } from '../../../services/crudServices/best.service';
|
|
||||||
import { HappinessGroupService } from '../../../services/crudServices/happiness-group.service';
|
|
||||||
import { LineGroup, LineService } from '../../../services/line.service';
|
|
||||||
import { MsgBoxService } from '../../../services/msg-box.service';
|
|
||||||
import { ADButtons, AlertDlgComponent } from '../../../ui/alert-dlg/alert-dlg.component';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ngx-best-list-dlg',
|
|
||||||
templateUrl: './best-list-dlg.component.html',
|
|
||||||
styleUrls: ['./best-list-dlg.component.scss']
|
|
||||||
})
|
|
||||||
export class BestListDlgComponent implements OnInit {
|
|
||||||
|
|
||||||
processing: boolean = false;
|
|
||||||
isAdding: boolean = false;
|
|
||||||
group: PastoralDomain;
|
|
||||||
datum: HappinessBEST;
|
|
||||||
constructor(
|
|
||||||
private dlgRef: NbDialogRef<BestListDlgComponent>,
|
|
||||||
private msgBpxService: MsgBoxService,
|
|
||||||
private happinessGroupService: HappinessGroupService,
|
|
||||||
private toastrService: NbToastrService,
|
|
||||||
private bestService: BestService,
|
|
||||||
private lineService: LineService
|
|
||||||
) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.group.bests = this.group.bests.sort((a, b) => 0 - (a.name < b.name ? 1 : -1));
|
|
||||||
}
|
|
||||||
|
|
||||||
close() {
|
|
||||||
this.dlgRef.close();
|
|
||||||
}
|
|
||||||
update() {
|
|
||||||
this.dlgRef.close(this.datum);
|
|
||||||
}
|
|
||||||
addBest() {
|
|
||||||
this.msgBpxService.showInputbox('Add Best', 'Please input Best\'s Name').pipe(first()).subscribe(result => {
|
|
||||||
if (result) {
|
|
||||||
let obj = { groupId: this.group.id, id: '', name: result } as HappinessBEST;
|
|
||||||
this.bestService.createOrUpdate(obj).pipe(first()).subscribe(result => {
|
|
||||||
this.dlgRef.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
copyBestUrl(best: HappinessBEST) {
|
|
||||||
|
|
||||||
var dummy = document.createElement("textarea");
|
|
||||||
document.body.appendChild(dummy);
|
|
||||||
dummy.value = `${environment.invitationUrl}${best.id}`;
|
|
||||||
dummy.select();
|
|
||||||
document.execCommand("copy");
|
|
||||||
document.body.removeChild(dummy);
|
|
||||||
this.toastrService.success(dummy.value, "複製地址至剪貼簿!");
|
|
||||||
}
|
|
||||||
copyBestList() {
|
|
||||||
let list = "".concat(...this.group.bests.map(b => `${b.name}\t\t: ${environment.invitationUrl}${b.id}\r\n`));
|
|
||||||
var dummy = document.createElement("textarea");
|
|
||||||
document.body.appendChild(dummy);
|
|
||||||
dummy.value = list;
|
|
||||||
dummy.select();
|
|
||||||
document.execCommand("copy");
|
|
||||||
document.body.removeChild(dummy);
|
|
||||||
this.toastrService.success(dummy.value, "複製地址至剪貼簿!");
|
|
||||||
|
|
||||||
this.lineService.pushLineMessage(LineGroup.Chris, list);
|
|
||||||
|
|
||||||
}
|
|
||||||
downloadBestQRCode(best: HappinessBEST) {
|
|
||||||
|
|
||||||
this.happinessGroupService.getBestQrCode(best.name + ".png", best.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
nb-card {
|
|
||||||
max-height: 90vh;
|
|
||||||
width: 700px;
|
|
||||||
}
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import { NbDialogRef, NbDialogService } from '@nebular/theme';
|
|
||||||
import { first } from 'rxjs/operators';
|
|
||||||
import { HappinessWeek } from '../../../entity/HappinessGroup';
|
|
||||||
import { PastoralDomain } from '../../../entity/PastoralDomain';
|
|
||||||
import { NumberUtils } from '../../../utilities/number-utils';
|
|
||||||
import { HappinessWeekEditorComponent } from '../happiness-week-editor/happiness-week-editor.component';
|
|
||||||
import { WeekTaskEditorComponent } from '../week-task-editor/week-task-editor.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ngx-happiness-week-list-dlg',
|
|
||||||
templateUrl: './happiness-week-list-dlg.component.html',
|
|
||||||
styleUrls: ['./happiness-week-list-dlg.component.scss']
|
|
||||||
})
|
|
||||||
export class HappinessWeekListDlgComponent implements OnInit {
|
|
||||||
|
|
||||||
group: PastoralDomain;
|
|
||||||
constructor(
|
|
||||||
private dlgRef: NbDialogRef<any>,
|
|
||||||
private dlgService: NbDialogService
|
|
||||||
) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
close() {
|
|
||||||
this.dlgRef.close();
|
|
||||||
}
|
|
||||||
openEditDlg(week: HappinessWeek) {
|
|
||||||
this.dlgService.open(HappinessWeekEditorComponent, {
|
|
||||||
context: {
|
|
||||||
data: week
|
|
||||||
}
|
|
||||||
}).onClose.pipe(first()).subscribe(result => {
|
|
||||||
if (result) this.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
openTaskDlg(week: HappinessWeek) {
|
|
||||||
this.dlgService.open(WeekTaskEditorComponent, {
|
|
||||||
context: {
|
|
||||||
data: week,
|
|
||||||
allData: this.group.happinessWeeks
|
|
||||||
}
|
|
||||||
}).onClose.pipe(first()).subscribe(result => {
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
weekDisplay(seq: number) {
|
|
||||||
return `W${seq} ${this.group.happinessWeeks[seq - 1].topic}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
<form #form="ngForm">
|
|
||||||
<nb-card>
|
|
||||||
<nb-card-header>
|
|
||||||
第 {{data.seq}} 周 {{data.topic}} 分工
|
|
||||||
</nb-card-header>
|
|
||||||
<nb-card-body *ngIf="data">
|
|
||||||
<div class="row" *ngFor="let task of data.tasks;let i = index">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class='form-group'>
|
|
||||||
<label for='tasker{{i}}' class='label'>{{getTaskTitle(task.type)}}</label>
|
|
||||||
<op-drop-down name="tasker{{i}}" [editable]="true" [(ngModel)]="task.tasker"
|
|
||||||
[source]="taskrOptions">
|
|
||||||
</op-drop-down>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-8">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="content{{i}}" class="label">內容</label>
|
|
||||||
<input type="text" name="content{{i}}" nbInput fullWidth id="content{{i}}"
|
|
||||||
[(ngModel)]="task.content">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</nb-card-body>
|
|
||||||
<nb-card-footer>
|
|
||||||
<button class="float-right" nbButton hero status="danger" size="small" (click)="close()"
|
|
||||||
[nbSpinner]="processing">
|
|
||||||
Close
|
|
||||||
</button>
|
|
||||||
<button class="float-right mr-2" nbButton hero status="primary" size="small"
|
|
||||||
(click)="!form.invalid&&!processing&&update()" [disabled]="form.invalid" [nbSpinner]="processing">
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</nb-card-footer>
|
|
||||||
</nb-card>
|
|
||||||
</form>
|
|
||||||
@ -1,79 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import { NbDialogRef } from '@nebular/theme';
|
|
||||||
import { HappinessTask, HappinessTaskType, HappinessWeek } from '../../../entity/HappinessGroup';
|
|
||||||
import { HappinessTaskService } from '../../../services/crudServices/happiness-group.service';
|
|
||||||
import { first } from 'rxjs/operators';
|
|
||||||
import { DropDownOption } from '../../../entity/dropDownOption';
|
|
||||||
import { StringUtils } from '../../../utilities/string-utils';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ngx-week-task-editor',
|
|
||||||
templateUrl: './week-task-editor.component.html',
|
|
||||||
styleUrls: ['./week-task-editor.component.scss']
|
|
||||||
})
|
|
||||||
export class WeekTaskEditorComponent implements OnInit {
|
|
||||||
processing: boolean = false;
|
|
||||||
allData: HappinessWeek[];
|
|
||||||
data: HappinessWeek;
|
|
||||||
taskrOptions: DropDownOption[] = [];
|
|
||||||
constructor(
|
|
||||||
private happinessTaskService: HappinessTaskService,
|
|
||||||
private dlgRef: NbDialogRef<WeekTaskEditorComponent>
|
|
||||||
) {
|
|
||||||
|
|
||||||
}
|
|
||||||
ngOnInit(): void {
|
|
||||||
if (this.data.tasks.length == 0) {
|
|
||||||
this.data.tasks = [];
|
|
||||||
for (let i = HappinessTaskType.IceBreak; i <= HappinessTaskType.Dessert; i++) {
|
|
||||||
this.data.tasks.push(
|
|
||||||
{
|
|
||||||
weekId: this.data.id,
|
|
||||||
id: 'new',
|
|
||||||
type: i as HappinessTaskType,
|
|
||||||
tasker: '',
|
|
||||||
content: ''
|
|
||||||
} as HappinessTask
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let names = [] as string[];
|
|
||||||
this.allData.forEach(week => {
|
|
||||||
if (week.tasks) {
|
|
||||||
names = names.concat(week.tasks.map(t => t.tasker.trim()));
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.taskrOptions = names.filter(function (item, pos) {
|
|
||||||
return !StringUtils.isNullOrWhitespace(item) && names.indexOf(item) == pos;
|
|
||||||
}).map(name => new DropDownOption(name, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
close() {
|
|
||||||
this.dlgRef.close();
|
|
||||||
}
|
|
||||||
update() {
|
|
||||||
if (this.processing == false) {
|
|
||||||
|
|
||||||
this.processing = true;
|
|
||||||
|
|
||||||
this.happinessTaskService.createOrUpdateAll(this.data.tasks).pipe(first()).subscribe(result => {
|
|
||||||
this.processing = false;
|
|
||||||
this.dlgRef.close(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getTaskTitle(t: HappinessTaskType) {
|
|
||||||
switch (t) {
|
|
||||||
case HappinessTaskType.IceBreak: return '帶遊戲';
|
|
||||||
case HappinessTaskType.Worship: return '唱歌';
|
|
||||||
case HappinessTaskType.Testimony: return '見證';
|
|
||||||
case HappinessTaskType.Message: return '信息';
|
|
||||||
case HappinessTaskType.Gift: return '準備禮物';
|
|
||||||
case HappinessTaskType.Dessert: return '準備點心';
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -33,7 +33,7 @@ export class LineMessagingAccountEditorComponent implements OnInit {
|
|||||||
|
|
||||||
this.processing = true;
|
this.processing = true;
|
||||||
|
|
||||||
let func = this.isAdding ? this.lineMessagingAccountService.createOrUpdate(this.data) : this.lineMessagingAccountService.update(this.data);
|
let func = this.lineMessagingAccountService.createOrUpdate(this.data);//this.isAdding ? this.lineMessagingAccountService.createOrUpdate(this.data) : this.lineMessagingAccountService.update(this.data);
|
||||||
func.pipe(first()).subscribe(result => {
|
func.pipe(first()).subscribe(result => {
|
||||||
this.processing = false;
|
this.processing = false;
|
||||||
if (result) {
|
if (result) {
|
||||||
|
|||||||
@ -3,11 +3,11 @@ import { ActivatedRoute } from '@angular/router';
|
|||||||
import { NbDialogService } from '@nebular/theme';
|
import { NbDialogService } from '@nebular/theme';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from 'rxjs/operators';
|
||||||
import { StateService } from '../../@core/utils';
|
|
||||||
import { Log, LogLevel } from '../../entity/Log';
|
import { Log, LogLevel } from '../../entity/Log';
|
||||||
import { ScreenBase } from '../../ScreenBase';
|
import { ScreenBase } from '../../ScreenBase';
|
||||||
import { LogService } from '../../services/crudServices/log.service';
|
import { LogService } from '../../services/crudServices/log.service';
|
||||||
import { MsgBoxService } from '../../services/msg-box.service';
|
import { MsgBoxService } from '../../services/msg-box.service';
|
||||||
|
import { StateService } from '../../services/state.service';
|
||||||
import { FancyTag } from '../../ui/fancy-table/fancy-row-column.model';
|
import { FancyTag } from '../../ui/fancy-table/fancy-row-column.model';
|
||||||
import { FancySettings } from '../../ui/fancy-table/fancy-settings.model';
|
import { FancySettings } from '../../ui/fancy-table/fancy-settings.model';
|
||||||
import { FancyTableComponent } from '../../ui/fancy-table/fancy-table.component';
|
import { FancyTableComponent } from '../../ui/fancy-table/fancy-table.component';
|
||||||
|
|||||||
@ -3,17 +3,18 @@ import { ActivatedRoute } from '@angular/router';
|
|||||||
import { NbDialogService } from '@nebular/theme';
|
import { NbDialogService } from '@nebular/theme';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from 'rxjs/operators';
|
||||||
import { StateService } from '../../@core/utils';
|
|
||||||
import { FamilyMember } from '../../entity/Member';
|
import { FamilyMember } from '../../entity/Member';
|
||||||
import { DomainType, PastoralDomain } from '../../entity/PastoralDomain';
|
import { DomainType, PastoralDomain } from '../../entity/PastoralDomain';
|
||||||
|
import { BestListDlgComponent } from '../../happiness/best-list-dlg/best-list-dlg.component';
|
||||||
|
import { HappinessWeekListDlgComponent } from '../../happiness/happiness-week-list-dlg/happiness-week-list-dlg.component';
|
||||||
|
import { DomainMemberShipService } from '../../services/crudServices/domain-member-ship.service';
|
||||||
import { FamilyMemberService } from '../../services/crudServices/family-member.service';
|
import { FamilyMemberService } from '../../services/crudServices/family-member.service';
|
||||||
import { PastoralDomainService } from '../../services/crudServices/pastoral-domain.service';
|
import { PastoralDomainService } from '../../services/crudServices/pastoral-domain.service';
|
||||||
import { MsgBoxService } from '../../services/msg-box.service';
|
import { MsgBoxService } from '../../services/msg-box.service';
|
||||||
|
import { StateService } from '../../services/state.service';
|
||||||
import { FancySettings } from '../../ui/fancy-table/fancy-settings.model';
|
import { FancySettings } from '../../ui/fancy-table/fancy-settings.model';
|
||||||
import { FancyTableComponent } from '../../ui/fancy-table/fancy-table.component';
|
import { FancyTableComponent } from '../../ui/fancy-table/fancy-table.component';
|
||||||
import { ObjectUtils } from '../../utilities/object-utils';
|
import { ObjectUtils } from '../../utilities/object-utils';
|
||||||
import { BestListDlgComponent } from '../happiness-groups/best-list-dlg/best-list-dlg.component';
|
|
||||||
import { HappinessWeekListDlgComponent } from '../happiness-groups/happiness-week-list-dlg/happiness-week-list-dlg.component';
|
|
||||||
import { PastoralDomainEditorComponent } from './pastoral-domain-editor/pastoral-domain-editor.component';
|
import { PastoralDomainEditorComponent } from './pastoral-domain-editor/pastoral-domain-editor.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -35,7 +36,8 @@ export class PastoralDomainsComponent implements OnInit {
|
|||||||
private dlgService: NbDialogService,
|
private dlgService: NbDialogService,
|
||||||
protected stateService: StateService,
|
protected stateService: StateService,
|
||||||
protected route: ActivatedRoute,
|
protected route: ActivatedRoute,
|
||||||
private memberService: FamilyMemberService
|
private memberService: FamilyMemberService,
|
||||||
|
private memberShipService: DomainMemberShipService
|
||||||
|
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@ -87,6 +89,15 @@ export class PastoralDomainsComponent implements OnInit {
|
|||||||
callback: (datum, element) => {
|
callback: (datum, element) => {
|
||||||
this.openHappinessWeekListDlg(datum);
|
this.openHappinessWeekListDlg(datum);
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: true,
|
||||||
|
id: 'members',
|
||||||
|
title: 'Members',
|
||||||
|
icon: 'people-outline',
|
||||||
|
callback: (datum, element) => {
|
||||||
|
this.openMemberAssignDlg(datum);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
onContextMenuOpening: (datum, menuItems) => {
|
onContextMenuOpening: (datum, menuItems) => {
|
||||||
@ -94,9 +105,18 @@ export class PastoralDomainsComponent implements OnInit {
|
|||||||
menuItems.find(i => i.id == 'edit').visible = !!datum;
|
menuItems.find(i => i.id == 'edit').visible = !!datum;
|
||||||
menuItems.find(i => i.id == 'happinessBest').visible = datum.type == DomainType.HappinessGroup;
|
menuItems.find(i => i.id == 'happinessBest').visible = datum.type == DomainType.HappinessGroup;
|
||||||
menuItems.find(i => i.id == 'happinessWeek').visible = datum.type == DomainType.HappinessGroup;
|
menuItems.find(i => i.id == 'happinessWeek').visible = datum.type == DomainType.HappinessGroup;
|
||||||
|
//menuItems.find(i => i.id == 'members').visible = datum.type == DomainType.HappinessGroup;
|
||||||
return datum;
|
return datum;
|
||||||
},
|
},
|
||||||
columns: [
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
title: 'Type',
|
||||||
|
type: 'number',
|
||||||
|
group: true,
|
||||||
|
visible: false,
|
||||||
|
groupValuePrepareFunction: (v) => this.getDomainTypeName(v.type)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
title: 'Name',
|
title: 'Name',
|
||||||
@ -108,7 +128,7 @@ export class PastoralDomainsComponent implements OnInit {
|
|||||||
name: 'description',
|
name: 'description',
|
||||||
title: 'Description',
|
title: 'Description',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
widthPx: 200,
|
widthPct: 70,
|
||||||
//valuePrepareFunction: (item) => ,
|
//valuePrepareFunction: (item) => ,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -136,7 +156,6 @@ export class PastoralDomainsComponent implements OnInit {
|
|||||||
// },
|
// },
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
};
|
};
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
@ -222,5 +241,33 @@ export class PastoralDomainsComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getDomainTypeName(type: DomainType): string {
|
||||||
|
switch (type) {
|
||||||
|
case DomainType.CellGroup: return "細胞小組";
|
||||||
|
case DomainType.HappinessGroup: return "幸福小組";
|
||||||
|
case DomainType.CellGroupCoworker: return "細胞同工";
|
||||||
|
case DomainType.ChurchCoworker: return "教會事工";
|
||||||
|
case DomainType.Administrator: return "管理員";
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private openMemberAssignDlg(datum: PastoralDomain) {
|
||||||
|
|
||||||
|
// this.msgBoxService.showListBox<FamilyMember>(
|
||||||
|
// `Members in ${datum.name}`,
|
||||||
|
// this.members,
|
||||||
|
// 'id',
|
||||||
|
// datum.familyMembers.map(m => m.id),
|
||||||
|
// (e) => `${e.firstName} ${e.lastName} (${e.email})`
|
||||||
|
// ).pipe(first()).subscribe(result => {
|
||||||
|
// if (result) {
|
||||||
|
|
||||||
|
// datum.familyMembers = result;
|
||||||
|
// this.memberShipService.updateMembersInGroup(datum).pipe(first()).subscribe(result => {
|
||||||
|
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,7 +77,7 @@ export const routes: Routes = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'CellGroup', loadChildren: () => import('./cell-group/cell-group.module').then(m => m.CellGroupModule),
|
path: 'myapp', loadChildren: () => import('./cell-group/cell-group.module').then(m => m.CellGroupModule),
|
||||||
canActivateChild: [AuthGuardService],
|
canActivateChild: [AuthGuardService],
|
||||||
data: {
|
data: {
|
||||||
roles: Role.All
|
roles: Role.All
|
||||||
|
|||||||
93
src/app/cell-group/MyAppBase.ts
Normal file
93
src/app/cell-group/MyAppBase.ts
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
import { basename } from "path";
|
||||||
|
import { Observable, Subject } from "rxjs";
|
||||||
|
import { ScreenBase } from "../ScreenBase";
|
||||||
|
import { ICrudService } from "../services/crudServices/crud.service";
|
||||||
|
import { PastoralDomainService } from "../services/crudServices/pastoral-domain.service";
|
||||||
|
import { StateService } from "../services/state.service";
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
import { PastoralDomain } from "../entity/PastoralDomain";
|
||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export abstract class MyAppBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
protected stateService: StateService,
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
protected pastoralDomainService: PastoralDomainService
|
||||||
|
) {
|
||||||
|
// super(pastoralDomainService, stateService, route);
|
||||||
|
// this.isSnapshotView = true;
|
||||||
|
}
|
||||||
|
isLoading: boolean = true;
|
||||||
|
redirectIfNoDomains: boolean = true;
|
||||||
|
|
||||||
|
pageGroupId: string;
|
||||||
|
|
||||||
|
private domainInitialized = new Subject();;
|
||||||
|
ngOnInit(): void {
|
||||||
|
|
||||||
|
this.isLoading = true;
|
||||||
|
// this.route.paramMap.subscribe((params: ParamMap) => {
|
||||||
|
// this.id = +params.get('id')
|
||||||
|
// });
|
||||||
|
this.route.paramMap.pipe(first()).subscribe(params => {
|
||||||
|
if (params.get('groupId')) {
|
||||||
|
this.pageGroupId = params.get('groupId');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pastoralDomainService.initialized.takeUntil(this.domainInitialized).subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
this.domainInitialized.next();
|
||||||
|
if (this.redirectIfNoDomains) {
|
||||||
|
if (this.pageGroupId && !this.domains.find(d => d.id == this.pageGroupId)) {
|
||||||
|
this.pastoralDomainService.joinDomain(this.pageGroupId).pipe(first()).subscribe(result => {
|
||||||
|
this.pageOnInit();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else if (this.domains.length == 0) {
|
||||||
|
//TODO:SetUser
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pageOnInit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public get domains(): PastoralDomain[] {
|
||||||
|
return this.pastoralDomainService.domains;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract pageOnInit(): void;
|
||||||
|
|
||||||
|
get saveMethod(): Observable<any> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public get happinessGroup(): PastoralDomain {
|
||||||
|
return this.pastoralDomainService.myHappinessGroup;
|
||||||
|
}
|
||||||
|
public get cellGroup(): PastoralDomain {
|
||||||
|
return this.pastoralDomainService.myCellGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get currentDomain(): PastoralDomain {
|
||||||
|
return this.domains.find(d => d.id == this.pageGroupId);
|
||||||
|
}
|
||||||
|
public get currentDomainName(): string {
|
||||||
|
if (this.domains && this.pageGroupId) {
|
||||||
|
//let group = this.domains.find(d => d.id == this.pageGroupId);
|
||||||
|
|
||||||
|
return this.domains.find(d => d.id == this.pageGroupId)?.name;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,25 +2,58 @@ import { NgModule } from '@angular/core';
|
|||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
import { NbMenuItem } from '@nebular/theme';
|
import { NbMenuItem } from '@nebular/theme';
|
||||||
import { Role } from '../entity/Auth';
|
import { Role } from '../entity/Auth';
|
||||||
|
import { DomainType } from '../entity/PastoralDomain';
|
||||||
import { CellGroupComponent } from './cell-group.component';
|
import { CellGroupComponent } from './cell-group.component';
|
||||||
import { DinnerComponent } from './dinner/dinner.component';
|
import { DinnerComponent } from './dinner/dinner.component';
|
||||||
|
import { FinanceComponent } from './finance/finance.component';
|
||||||
import { GoogleLoginComponent } from './google-login/google-login.component';
|
import { GoogleLoginComponent } from './google-login/google-login.component';
|
||||||
|
import { BestListComponent, HappinessWeekListComponent } from './happiness-group/happiness-group.component';
|
||||||
import { PrayerComponent } from './prayer/prayer.component';
|
import { PrayerComponent } from './prayer/prayer.component';
|
||||||
|
import { UserProfileComponent } from './user-profile/user-profile.component';
|
||||||
export class CellGroupRoutingConfig {
|
export class CellGroupRoutingConfig {
|
||||||
public static MENU_ITEMS: NbMenuItem[] = [
|
public static MENU_ITEMS: NbMenuItem[] = [
|
||||||
|
|
||||||
{
|
{
|
||||||
title: '小組禱告',
|
title: '細胞小組',
|
||||||
icon: 'people-outline',
|
icon: 'people-outline',
|
||||||
link: '/CellGroup/prayer',
|
children: [
|
||||||
home: true,
|
|
||||||
|
{
|
||||||
|
title: '小組禱告',
|
||||||
|
//icon: 'people-outline',
|
||||||
|
link: '/myapp/prayer'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '小組晚餐',
|
title: '小組晚餐',
|
||||||
icon: 'people-outline',
|
//icon: 'people-outline',
|
||||||
link: '/CellGroup/dinner',
|
link: '/myapp/dinner',
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
data: DomainType.CellGroup
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '幸福小組',
|
||||||
|
icon: 'smiling-face-outline',
|
||||||
|
children: [
|
||||||
|
|
||||||
|
{
|
||||||
|
title: 'Bests',
|
||||||
|
//icon: 'people-outline',
|
||||||
|
link: '/myapp/bests'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '幸福周',
|
||||||
|
//icon: 'people-outline',
|
||||||
|
link: '/myapp/happinessWeeks',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '財務表',
|
||||||
|
//icon: 'people-outline',
|
||||||
|
link: '/myapp/finance',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
data: DomainType.HappinessGroup
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
@ -29,7 +62,16 @@ const routes: Routes = [
|
|||||||
children:
|
children:
|
||||||
[
|
[
|
||||||
{ path: 'dinner', component: DinnerComponent, },
|
{ path: 'dinner', component: DinnerComponent, },
|
||||||
|
{ path: 'dinner/:groupId', component: DinnerComponent, },
|
||||||
{ path: 'prayer', component: PrayerComponent, },
|
{ path: 'prayer', component: PrayerComponent, },
|
||||||
|
{ path: 'prayer/:groupId', component: PrayerComponent, },
|
||||||
|
{ path: 'profile', component: UserProfileComponent, },
|
||||||
|
{ path: 'bests', component: BestListComponent, },
|
||||||
|
{ path: 'bests/:groupId', component: BestListComponent, },
|
||||||
|
{ path: 'happinessWeeks', component: HappinessWeekListComponent, },
|
||||||
|
{ path: 'happinessWeeks/:groupId', component: HappinessWeekListComponent, },
|
||||||
|
{ path: 'finance/:groupId', component: FinanceComponent, },
|
||||||
|
|
||||||
{
|
{
|
||||||
path: 'management', component: GoogleLoginComponent,
|
path: 'management', component: GoogleLoginComponent,
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<ngx-one-column-layout>
|
<ngx-one-column-layout>
|
||||||
<nb-menu [items]="MENU_ITEMS"></nb-menu>
|
<nb-menu [items]="MENU_ITEMS" tag="NavMenu"></nb-menu>
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</ngx-one-column-layout>
|
</ngx-one-column-layout>
|
||||||
@ -1,5 +1,9 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { NbMenuItem } from '@nebular/theme';
|
||||||
|
import { PastoralDomainService } from '../services/crudServices/pastoral-domain.service';
|
||||||
|
import { ObjectUtils } from '../utilities/object-utils';
|
||||||
import { CellGroupRoutingConfig } from './cell-group-routing.module';
|
import { CellGroupRoutingConfig } from './cell-group-routing.module';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ngx-cell-group',
|
selector: 'ngx-cell-group',
|
||||||
@ -8,10 +12,45 @@ import { CellGroupRoutingConfig } from './cell-group-routing.module';
|
|||||||
})
|
})
|
||||||
export class CellGroupComponent implements OnInit {
|
export class CellGroupComponent implements OnInit {
|
||||||
|
|
||||||
MENU_ITEMS = CellGroupRoutingConfig.MENU_ITEMS;
|
MENU_ITEMS = ObjectUtils.CloneValue(CellGroupRoutingConfig.MENU_ITEMS);
|
||||||
constructor() { }
|
constructor(
|
||||||
|
private pastoralDomainService: PastoralDomainService
|
||||||
ngOnInit(): void {
|
) {
|
||||||
|
let subscription = pastoralDomainService.initialized.subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
this.initializeSideMenu();
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private initializeSideMenu() {
|
||||||
|
|
||||||
|
for (let i = 0; i < this.MENU_ITEMS.length; i++) {
|
||||||
|
const item = this.MENU_ITEMS[i];
|
||||||
|
this.checkDisplayItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private checkDisplayItem(item: NbMenuItem) {
|
||||||
|
if (item.data != undefined) {
|
||||||
|
var group = this.pastoralDomainService.domains.find(d => d.type == item.data);
|
||||||
|
if (!group) {
|
||||||
|
item.hidden = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item.title = `${group.name}`;
|
||||||
|
item.children.forEach(element => {
|
||||||
|
element.link += `/${group.id}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (item.children) {
|
||||||
|
item.children.forEach(element => {
|
||||||
|
this.checkDisplayItem(element);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,19 @@ import { CellGroupRoutingModule } from './cell-group-routing.module';
|
|||||||
import { CellGroupComponent } from './cell-group.component';
|
import { CellGroupComponent } from './cell-group.component';
|
||||||
import { DinnerComponent } from './dinner/dinner.component';
|
import { DinnerComponent } from './dinner/dinner.component';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { NbButtonModule, NbCardModule, NbIconModule, NbInputModule, NbMenuModule, NbSpinnerModule, NbToastrModule, NbToggleModule } from '@nebular/theme';
|
import { NbActionsModule, NbButtonModule, NbCardModule, NbCheckboxModule, NbIconModule, NbInputModule, NbMenuModule, NbSpinnerModule, NbToastrModule, NbToggleModule } from '@nebular/theme';
|
||||||
import { ThemeModule } from '../@theme/theme.module';
|
import { ThemeModule } from '../@theme/theme.module';
|
||||||
import { GoogleLoginComponent } from './google-login/google-login.component';
|
import { GoogleLoginComponent } from './google-login/google-login.component';
|
||||||
import { PrayerComponent } from './prayer/prayer.component';
|
import { PrayerComponent } from './prayer/prayer.component';
|
||||||
import { UserProfileComponent } from './user-profile/user-profile.component';
|
import { UserProfileComponent } from './user-profile/user-profile.component';
|
||||||
|
import { DateInputModule } from '../ui/date-input/date-input.module';
|
||||||
|
import { DropDownListModule } from '../ui/drop-down-list/drop-down-list.module';
|
||||||
|
import { HappinessModule } from '../happiness/happiness.module';
|
||||||
|
import { BestListComponent, HappinessWeekListComponent } from './happiness-group/happiness-group.component';
|
||||||
|
import { JoinDomainComponent } from './join-domain/join-domain.component';
|
||||||
|
import { FinanceComponent } from './finance/finance.component';
|
||||||
|
import { AddContributionDlgComponent } from './finance/add-contribution-dlg/add-contribution-dlg.component';
|
||||||
|
import { FancyTableModule } from '../ui/fancy-table/fancy-table.module';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -18,7 +26,12 @@ import { UserProfileComponent } from './user-profile/user-profile.component';
|
|||||||
DinnerComponent,
|
DinnerComponent,
|
||||||
GoogleLoginComponent,
|
GoogleLoginComponent,
|
||||||
PrayerComponent,
|
PrayerComponent,
|
||||||
UserProfileComponent
|
UserProfileComponent,
|
||||||
|
BestListComponent,
|
||||||
|
HappinessWeekListComponent,
|
||||||
|
JoinDomainComponent,
|
||||||
|
FinanceComponent,
|
||||||
|
AddContributionDlgComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
ThemeModule,
|
ThemeModule,
|
||||||
@ -32,8 +45,13 @@ import { UserProfileComponent } from './user-profile/user-profile.component';
|
|||||||
NbToastrModule,
|
NbToastrModule,
|
||||||
NbToggleModule,
|
NbToggleModule,
|
||||||
NbIconModule,
|
NbIconModule,
|
||||||
NbMenuModule
|
NbMenuModule,
|
||||||
|
NbActionsModule,
|
||||||
|
DateInputModule,
|
||||||
|
NbCheckboxModule,
|
||||||
|
DropDownListModule,
|
||||||
|
HappinessModule,
|
||||||
|
FancyTableModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CellGroupModule { }
|
export class CellGroupModule { }
|
||||||
|
|||||||
@ -11,14 +11,17 @@ import { AuthService } from '../../services/auth.service';
|
|||||||
import { DateUtils } from '../../utilities/date-utils';
|
import { DateUtils } from '../../utilities/date-utils';
|
||||||
import { NumberUtils } from '../../utilities/number-utils';
|
import { NumberUtils } from '../../utilities/number-utils';
|
||||||
import { CellGroupRoutineEventsService } from '../../services/crudServices/cell-group-routine-events.service';
|
import { CellGroupRoutineEventsService } from '../../services/crudServices/cell-group-routine-events.service';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { PastoralDomainService } from '../../services/crudServices/pastoral-domain.service';
|
||||||
|
import { MyAppBase } from '../MyAppBase';
|
||||||
|
import { StateService } from '../../services/state.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ngx-dinner',
|
selector: 'ngx-dinner',
|
||||||
templateUrl: './dinner.component.html',
|
templateUrl: './dinner.component.html',
|
||||||
styleUrls: ['./dinner.component.scss']
|
styleUrls: ['./dinner.component.scss']
|
||||||
})
|
})
|
||||||
export class DinnerComponent implements OnInit {
|
export class DinnerComponent extends MyAppBase {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private cellGroupRoutineEventsService: CellGroupRoutineEventsService,
|
private cellGroupRoutineEventsService: CellGroupRoutineEventsService,
|
||||||
private messageService: MsgBoxService,
|
private messageService: MsgBoxService,
|
||||||
@ -26,10 +29,12 @@ export class DinnerComponent implements OnInit {
|
|||||||
private sessionService: SessionService,
|
private sessionService: SessionService,
|
||||||
private lineService: LineService,
|
private lineService: LineService,
|
||||||
private cdRef: ChangeDetectorRef,
|
private cdRef: ChangeDetectorRef,
|
||||||
private headerService: HeaderService,
|
private authService: AuthService,
|
||||||
private authService: AuthService
|
protected stateService: StateService,
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
protected pastoralDomainService: PastoralDomainService
|
||||||
) {
|
) {
|
||||||
|
super(stateService, route, pastoralDomainService);
|
||||||
}
|
}
|
||||||
|
|
||||||
cellGroupEvent: CellGroupRoutineEvents;
|
cellGroupEvent: CellGroupRoutineEvents;
|
||||||
@ -40,10 +45,12 @@ export class DinnerComponent implements OnInit {
|
|||||||
isLoading: boolean = true;
|
isLoading: boolean = true;
|
||||||
processing: boolean = false;
|
processing: boolean = false;
|
||||||
|
|
||||||
ngOnInit(): void {
|
pageOnInit(): void {
|
||||||
this.headerService.setHeader("晚宴系統")
|
this.stateService.SetPageTitle("晚宴系統");
|
||||||
this.getAllData();
|
this.getAllData();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllData() {
|
getAllData() {
|
||||||
|
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
@ -70,7 +77,7 @@ export class DinnerComponent implements OnInit {
|
|||||||
|
|
||||||
this.processing = false;
|
this.processing = false;
|
||||||
this.toastrService.success('菜單更新完成!');
|
this.toastrService.success('菜單更新完成!');
|
||||||
this.lineService.pushCommandMessage('Cac4ac5a8d7fc52daa444d71dc7c360a9', 'dinner');
|
this.lineService.pushCommandMessage(this.cellGroupEvent.pastoralDomainId, 'dinner');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,36 @@
|
|||||||
|
<nb-card status="success">
|
||||||
|
<nb-card-header>
|
||||||
|
新增奉獻
|
||||||
|
</nb-card-header>
|
||||||
|
<nb-card-body>
|
||||||
|
<div class="row form-group">
|
||||||
|
<div class="col-6 col-md-4">
|
||||||
|
<div class='form-group'>
|
||||||
|
<label for='contributor' class='label'>奉獻人</label>
|
||||||
|
|
||||||
|
<input type="text" name="contributor" nbInput fullWidth id="contributor"
|
||||||
|
[(ngModel)]="contribution.contributor">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-6 col-md-3">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="costAmount" class="label">金額</label>
|
||||||
|
<input type="number" name="costAmount" nbInput fullWidth id="costAmount"
|
||||||
|
[(ngModel)]="contribution.amount">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-5">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="costContent" class="label">備註</label>
|
||||||
|
<input type="text" name="costContent" nbInput fullWidth id="costContent"
|
||||||
|
[(ngModel)]="contribution.comment">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nb-card-body>
|
||||||
|
<nb-card-footer>
|
||||||
|
<button class="float-right" nbButton hero status="danger" size="small" (click)="close()">Close</button>
|
||||||
|
<button class="float-right mr-2" nbButton hero status="primary" size="small" (click)="submit()">Submit</button>
|
||||||
|
</nb-card-footer>
|
||||||
|
</nb-card>
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AddContributionDlgComponent } from './add-contribution-dlg.component';
|
||||||
|
|
||||||
|
describe('AddContributionDlgComponent', () => {
|
||||||
|
let component: AddContributionDlgComponent;
|
||||||
|
let fixture: ComponentFixture<AddContributionDlgComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ AddContributionDlgComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AddContributionDlgComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { NbDialogRef } from '@nebular/theme';
|
||||||
|
import { Contribution } from '../../../entity/contribution.model';
|
||||||
|
import { DropDownOption } from '../../../entity/dropDownOption';
|
||||||
|
import { AuthService } from '../../../services/auth.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-add-contribution-dlg',
|
||||||
|
templateUrl: './add-contribution-dlg.component.html',
|
||||||
|
styleUrls: ['./add-contribution-dlg.component.scss']
|
||||||
|
})
|
||||||
|
export class AddContributionDlgComponent implements OnInit {
|
||||||
|
|
||||||
|
taskrOptions: DropDownOption[] = [];
|
||||||
|
contribution: Contribution;
|
||||||
|
constructor(
|
||||||
|
private authService: AuthService,
|
||||||
|
private dlgRef: NbDialogRef<AddContributionDlgComponent>
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.contribution = { time: new Date() } as Contribution;
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
this.dlgRef.close();
|
||||||
|
}
|
||||||
|
submit() {
|
||||||
|
if (this.contribution.contributor && this.contribution.amount > 0) {
|
||||||
|
this.dlgRef.close(this.contribution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
13
src/app/cell-group/finance/finance.component.html
Normal file
13
src/app/cell-group/finance/finance.component.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<nb-card [nbSpinner]="isLoading" nbSpinnerStatus="info" nbSpinnerSize="giant">
|
||||||
|
<nb-card-header>
|
||||||
|
{{currentDomainName}} 財務表
|
||||||
|
<nb-actions size="small" fullWidth class="float-right">
|
||||||
|
<nb-action icon="plus-outline" title="Add New" (click)="addContribution()"></nb-action>
|
||||||
|
</nb-actions>
|
||||||
|
</nb-card-header>
|
||||||
|
<nb-card-body>
|
||||||
|
<ng-container *ngIf="!isLoading">
|
||||||
|
<fancy-table [data]="contributions" [settings]="contributionSettings" [footerData]="summary"></fancy-table>
|
||||||
|
</ng-container>
|
||||||
|
</nb-card-body>
|
||||||
|
</nb-card>
|
||||||
0
src/app/cell-group/finance/finance.component.scss
Normal file
0
src/app/cell-group/finance/finance.component.scss
Normal file
25
src/app/cell-group/finance/finance.component.spec.ts
Normal file
25
src/app/cell-group/finance/finance.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { FinanceComponent } from './finance.component';
|
||||||
|
|
||||||
|
describe('FinanceComponent', () => {
|
||||||
|
let component: FinanceComponent;
|
||||||
|
let fixture: ComponentFixture<FinanceComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ FinanceComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(FinanceComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
208
src/app/cell-group/finance/finance.component.ts
Normal file
208
src/app/cell-group/finance/finance.component.ts
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { NbDialogService, NbToastrService } from '@nebular/theme';
|
||||||
|
import { Contribution } from '../../entity/contribution.model';
|
||||||
|
import { AuthService } from '../../services/auth.service';
|
||||||
|
import { ContributionService } from '../../services/crudServices/contribution.service';
|
||||||
|
import { PastoralDomainService } from '../../services/crudServices/pastoral-domain.service';
|
||||||
|
import { LineService } from '../../services/line.service';
|
||||||
|
import { MsgBoxService } from '../../services/msg-box.service';
|
||||||
|
import { SessionService } from '../../services/session.service';
|
||||||
|
import { StateService } from '../../services/state.service';
|
||||||
|
import { MyAppBase } from '../MyAppBase';
|
||||||
|
import { AddContributionDlgComponent } from './add-contribution-dlg/add-contribution-dlg.component';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
import { FancySettings } from '../../ui/fancy-table/fancy-settings.model';
|
||||||
|
import { ObjectUtils } from '../../utilities/object-utils';
|
||||||
|
import { NumberUtils } from '../../utilities/number-utils';
|
||||||
|
import { StringUtils } from '../../utilities/string-utils';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-finance',
|
||||||
|
templateUrl: './finance.component.html',
|
||||||
|
styleUrls: ['./finance.component.scss']
|
||||||
|
})
|
||||||
|
export class FinanceComponent extends MyAppBase {
|
||||||
|
|
||||||
|
contributions: Contribution[];
|
||||||
|
summary: Contribution[];
|
||||||
|
//#region Table Setting
|
||||||
|
contributionSettings = <FancySettings<Contribution>>{
|
||||||
|
contextMenuItems: [
|
||||||
|
// {
|
||||||
|
// id: 'add',
|
||||||
|
// enabled: true,
|
||||||
|
// title: 'Add New',
|
||||||
|
// icon: 'plus-circle-outline',
|
||||||
|
// callback: (datum, element) => {
|
||||||
|
// this.openEditingDialog(true);
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// id: 'edit',
|
||||||
|
// enabled: true,
|
||||||
|
// title: 'Edit',
|
||||||
|
// icon: 'edit',
|
||||||
|
// callback: (datum, element) => {
|
||||||
|
// this.openEditingDialog(false);
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
enabled: true,
|
||||||
|
id: 'delete',
|
||||||
|
title: 'Delete',
|
||||||
|
icon: 'trash-2-outline',
|
||||||
|
callback: (datum, element) => {
|
||||||
|
this.contributionService.delete(datum.id).pipe(first()).subscribe(result => {
|
||||||
|
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
onContextMenuOpening: (datum, menuItems) => {
|
||||||
|
menuItems.find(i => i.id == 'delete').visible = !!datum;
|
||||||
|
//menuItems.find(i => i.id == 'edit').visible = !!datum;
|
||||||
|
return datum;
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'time',
|
||||||
|
title: 'Time',
|
||||||
|
type: 'date',
|
||||||
|
widthPx: 120,
|
||||||
|
//valuePrepareFunction: (item) => ,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'contributor',
|
||||||
|
title: 'Contributor',
|
||||||
|
type: 'text',
|
||||||
|
widthPx: 150,
|
||||||
|
//valuePrepareFunction: (item) => ,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'amount',
|
||||||
|
title: 'Amount',
|
||||||
|
type: 'text',
|
||||||
|
widthPx: 100,
|
||||||
|
class: 'text-right',
|
||||||
|
footerClass: 'text-right',
|
||||||
|
valuePrepareFunction: getAmountDisplay,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'comment',
|
||||||
|
title: 'Comment',
|
||||||
|
type: 'text',
|
||||||
|
widthPx: 200,
|
||||||
|
//valuePrepareFunction: (item) => ,
|
||||||
|
},
|
||||||
|
|
||||||
|
],
|
||||||
|
showFooter: true
|
||||||
|
};
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private contributionService: ContributionService,
|
||||||
|
private messageService: MsgBoxService,
|
||||||
|
private toastrService: NbToastrService,
|
||||||
|
private sessionService: SessionService,
|
||||||
|
private lineService: LineService,
|
||||||
|
private cdRef: ChangeDetectorRef,
|
||||||
|
private authService: AuthService,
|
||||||
|
private dlgService: NbDialogService,
|
||||||
|
protected stateService: StateService,
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
protected pastoralDomainService: PastoralDomainService
|
||||||
|
) {
|
||||||
|
super(stateService, route, pastoralDomainService);
|
||||||
|
}
|
||||||
|
|
||||||
|
pageOnInit(): void {
|
||||||
|
this.initializeData();
|
||||||
|
}
|
||||||
|
|
||||||
|
addContribution() {
|
||||||
|
this.dlgService.open(AddContributionDlgComponent, {
|
||||||
|
context: {
|
||||||
|
|
||||||
|
}
|
||||||
|
}).onClose.pipe(first()).subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
result.groupId = this.currentDomain.id;
|
||||||
|
this.isLoading = true;
|
||||||
|
this.contributionService.createOrUpdate(result).pipe(first()).subscribe(result => {
|
||||||
|
this.refreshData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private refreshData() {
|
||||||
|
this.isLoading = true;
|
||||||
|
this.pastoralDomainService.initialize().pipe(first()).subscribe(result => {
|
||||||
|
this.initializeData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private initializeData() {
|
||||||
|
this.contributions = ObjectUtils.CloneValue(this.currentDomain.contributions);
|
||||||
|
this.summary = [];
|
||||||
|
|
||||||
|
let totalComment = '';
|
||||||
|
|
||||||
|
let totalAmount = this.contributions.map(d => d.amount).reduce((a, b) => a + b, 0);
|
||||||
|
//Append Cost
|
||||||
|
if (this.currentDomain.happinessWeeks) {
|
||||||
|
|
||||||
|
for (let i = 0; i < this.currentDomain.happinessWeeks.length; i++) {
|
||||||
|
const week = this.currentDomain.happinessWeeks[i];
|
||||||
|
let weekCost = 0;
|
||||||
|
for (let j = 0; j < week.costs.length; j++) {
|
||||||
|
const weekCostItem = week.costs[j];
|
||||||
|
this.contributions.push(
|
||||||
|
{
|
||||||
|
time: week.date,
|
||||||
|
contributor: `W${i + 1} - ${weekCostItem.tasker}`,
|
||||||
|
amount: -1 * weekCostItem.amount,
|
||||||
|
comment: weekCostItem.content
|
||||||
|
} as Contribution);
|
||||||
|
weekCost += weekCostItem.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weekCost > 0) {
|
||||||
|
|
||||||
|
this.contributions.push(
|
||||||
|
{
|
||||||
|
time: week.date,
|
||||||
|
contributor: `${week.topic} - Sub Total`,
|
||||||
|
amount: 0,
|
||||||
|
comment: '$ ' + NumberUtils.FormatCurrency(weekCost)
|
||||||
|
} as Contribution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let remainWeeks = this.currentDomain.happinessWeeks.filter(w => w.date >= new Date()).length;
|
||||||
|
|
||||||
|
totalAmount = this.contributions.map(d => d.amount).reduce((a, b) => a + b, 0);
|
||||||
|
totalComment = StringUtils.getHtmlBadge(`剩餘每周(${remainWeeks}) 預算: $${NumberUtils.FormatCurrency(totalAmount / remainWeeks)}`, 'info');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
this.summary.push(
|
||||||
|
{
|
||||||
|
time: null,
|
||||||
|
contributor: `Summary`,
|
||||||
|
amount: totalAmount,
|
||||||
|
comment: totalComment
|
||||||
|
} as Contribution);
|
||||||
|
this.isLoading = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getAmountDisplay(item: Contribution): string {
|
||||||
|
|
||||||
|
if (item.amount != 0) {
|
||||||
|
return StringUtils.getHtmlBadge(NumberUtils.FormatCurrency(item.amount), item.amount > 0 ? 'success' : 'warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
return "---------------";
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { PastoralDomainService } from '../../services/crudServices/pastoral-domain.service';
|
||||||
|
import { StateService } from '../../services/state.service';
|
||||||
|
import { MyAppBase } from '../MyAppBase';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-happiness-group',
|
||||||
|
template: `
|
||||||
|
<best-list [group]="happinessGroup"></best-list>
|
||||||
|
`,
|
||||||
|
styleUrls: ['./happiness-group.component.scss']
|
||||||
|
})
|
||||||
|
export class BestListComponent extends MyAppBase {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected stateService: StateService,
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
protected pastoralDomainService: PastoralDomainService
|
||||||
|
) {
|
||||||
|
super(stateService, route, pastoralDomainService);
|
||||||
|
}
|
||||||
|
pageOnInit(): void {
|
||||||
|
this.stateService.SetPageTitle("Best");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-happiness-week-group',
|
||||||
|
template: `<happiness-week-list [group]="happinessGroup"></happiness-week-list>
|
||||||
|
`,
|
||||||
|
styleUrls: ['./happiness-group.component.scss']
|
||||||
|
})
|
||||||
|
export class HappinessWeekListComponent extends MyAppBase {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected stateService: StateService,
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
protected pastoralDomainService: PastoralDomainService
|
||||||
|
) {
|
||||||
|
super(stateService, route, pastoralDomainService);
|
||||||
|
}
|
||||||
|
pageOnInit(): void {
|
||||||
|
this.stateService.SetPageTitle("Happiness Weeks");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
17
src/app/cell-group/join-domain/join-domain.component.html
Normal file
17
src/app/cell-group/join-domain/join-domain.component.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<nb-card status="success">
|
||||||
|
<nb-card-header>
|
||||||
|
加入小組
|
||||||
|
</nb-card-header>
|
||||||
|
<nb-card-body>
|
||||||
|
<div class='col-12 col-md-6'>
|
||||||
|
<div class='form-group'>
|
||||||
|
<label for='domain' class='label'>小組</label>
|
||||||
|
<op-drop-down name='domain' id='domain' [(ngModel)]='domainId' [source]='domainOptions'></op-drop-down>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nb-card-body>
|
||||||
|
<nb-card-footer>
|
||||||
|
<button class="float-right mr-2" fullWidth nbButton hero status="primary" size="large"
|
||||||
|
(click)="joinDomain()">加入小組</button>
|
||||||
|
</nb-card-footer>
|
||||||
|
</nb-card>
|
||||||
25
src/app/cell-group/join-domain/join-domain.component.spec.ts
Normal file
25
src/app/cell-group/join-domain/join-domain.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { JoinDomainComponent } from './join-domain.component';
|
||||||
|
|
||||||
|
describe('JoinDomainComponent', () => {
|
||||||
|
let component: JoinDomainComponent;
|
||||||
|
let fixture: ComponentFixture<JoinDomainComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ JoinDomainComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(JoinDomainComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
39
src/app/cell-group/join-domain/join-domain.component.ts
Normal file
39
src/app/cell-group/join-domain/join-domain.component.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { DomainType, PastoralDomain } from '../../entity/PastoralDomain';
|
||||||
|
import { PastoralDomainService } from '../../services/crudServices/pastoral-domain.service';
|
||||||
|
import { StateService } from '../../services/state.service';
|
||||||
|
import { MyAppBase } from '../MyAppBase';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
import { DropDownOption } from '../../entity/dropDownOption';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-join-domain',
|
||||||
|
templateUrl: './join-domain.component.html',
|
||||||
|
styleUrls: ['./join-domain.component.scss']
|
||||||
|
})
|
||||||
|
export class JoinDomainComponent extends MyAppBase {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected stateService: StateService,
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
protected pastoralDomainService: PastoralDomainService
|
||||||
|
) {
|
||||||
|
super(stateService, route, pastoralDomainService);
|
||||||
|
this.redirectIfNoDomains = false;
|
||||||
|
}
|
||||||
|
domainId: string;
|
||||||
|
allDomains: PastoralDomain[];
|
||||||
|
domainOptions: DropDownOption[] = [];
|
||||||
|
pageOnInit(): void {
|
||||||
|
this.isLoading = true;
|
||||||
|
this.pastoralDomainService.getAll().pipe(first()).subscribe(result => {
|
||||||
|
this.allDomains = result.filter(d => d.type == DomainType.CellGroup || d.type == DomainType.HappinessGroup);
|
||||||
|
this.domainOptions = this.allDomains.map(d => new DropDownOption(d.id, d.name));
|
||||||
|
this.isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
joinDomain() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,37 +1,38 @@
|
|||||||
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { NbToastrService } from '@nebular/theme';
|
import { NbToastrService } from '@nebular/theme';
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from 'rxjs/operators';
|
||||||
import { BindingHelper } from '../../entity/BindingHelper';
|
import { BindingHelper } from '../../entity/BindingHelper';
|
||||||
import { CellGroupRoutineEvents, CellGroupRoutineEventPrayer, CellGroupRoutineEventAttendee } from '../../entity/CellGroupRoutineEvents';
|
import { CellGroupRoutineEvents, CellGroupRoutineEventPrayer, CellGroupRoutineEventAttendee } from '../../entity/CellGroupRoutineEvents';
|
||||||
import { AuthService } from '../../services/auth.service';
|
import { AuthService } from '../../services/auth.service';
|
||||||
import { CellGroupRoutineEventsService } from '../../services/crudServices/cell-group-routine-events.service';
|
import { CellGroupRoutineEventsService } from '../../services/crudServices/cell-group-routine-events.service';
|
||||||
|
import { PastoralDomainService } from '../../services/crudServices/pastoral-domain.service';
|
||||||
import { HeaderService } from '../../services/header.service';
|
import { HeaderService } from '../../services/header.service';
|
||||||
import { LineService } from '../../services/line.service';
|
import { LineService } from '../../services/line.service';
|
||||||
import { MsgBoxService } from '../../services/msg-box.service';
|
import { MsgBoxService } from '../../services/msg-box.service';
|
||||||
import { SessionService } from '../../services/session.service';
|
import { SessionService } from '../../services/session.service';
|
||||||
|
import { StateService } from '../../services/state.service';
|
||||||
import { DateUtils } from '../../utilities/date-utils';
|
import { DateUtils } from '../../utilities/date-utils';
|
||||||
import { NumberUtils } from '../../utilities/number-utils';
|
import { NumberUtils } from '../../utilities/number-utils';
|
||||||
import { DinnerInfo } from '../dinner/dinner.component';
|
import { DinnerInfo } from '../dinner/dinner.component';
|
||||||
|
import { MyAppBase } from '../MyAppBase';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ngx-prayer',
|
selector: 'ngx-prayer',
|
||||||
templateUrl: './prayer.component.html',
|
templateUrl: './prayer.component.html',
|
||||||
styleUrls: ['./prayer.component.scss']
|
styleUrls: ['./prayer.component.scss']
|
||||||
})
|
})
|
||||||
export class PrayerComponent implements OnInit {
|
export class PrayerComponent extends MyAppBase {
|
||||||
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private cellGroupRoutineEventsService: CellGroupRoutineEventsService,
|
private cellGroupRoutineEventsService: CellGroupRoutineEventsService,
|
||||||
private messageService: MsgBoxService,
|
|
||||||
private toastrService: NbToastrService,
|
private toastrService: NbToastrService,
|
||||||
private sessionService: SessionService,
|
|
||||||
private lineService: LineService,
|
|
||||||
private cdRef: ChangeDetectorRef,
|
private cdRef: ChangeDetectorRef,
|
||||||
private headerService: HeaderService,
|
private authService: AuthService,
|
||||||
private authService: AuthService
|
protected stateService: StateService,
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
protected pastoralDomainService: PastoralDomainService
|
||||||
) {
|
) {
|
||||||
|
super(stateService, route, pastoralDomainService);
|
||||||
}
|
}
|
||||||
|
|
||||||
cellGroupEvent: CellGroupRoutineEvents;
|
cellGroupEvent: CellGroupRoutineEvents;
|
||||||
@ -42,8 +43,8 @@ export class PrayerComponent implements OnInit {
|
|||||||
isLoading: boolean = true;
|
isLoading: boolean = true;
|
||||||
processing: boolean = false;
|
processing: boolean = false;
|
||||||
|
|
||||||
ngOnInit(): void {
|
pageOnInit(): void {
|
||||||
this.headerService.setHeader("禱告中心")
|
this.stateService.SetPageTitle("禱告中心");
|
||||||
this.getAllData();
|
this.getAllData();
|
||||||
}
|
}
|
||||||
getAllData() {
|
getAllData() {
|
||||||
|
|||||||
@ -5,20 +5,21 @@
|
|||||||
</nb-card-header>
|
</nb-card-header>
|
||||||
<nb-card-body>
|
<nb-card-body>
|
||||||
<div class="row" *ngIf="data">
|
<div class="row" *ngIf="data">
|
||||||
<div class="col-md-3">
|
<div class="col-6 col-md-3">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="firstName" class="label">First Name</label>
|
<label for="firstName" class="label">First Name</label>
|
||||||
<input type="text" name="firstName" nbInput fullWidth id="firstName"
|
<input type="text" name="firstName" nbInput fullWidth id="firstName"
|
||||||
[(ngModel)]="data.firstName">
|
[(ngModel)]="data.firstName">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-6 col-md-3">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="lastName" class="label">Last Name</label>
|
<label for="lastName" class="label">Last Name</label>
|
||||||
<input type="text" name="lastName" nbInput fullWidth id="lastName" [(ngModel)]="data.lastName">
|
<input type="text" name="lastName" nbInput fullWidth id="lastName" [(ngModel)]="data.lastName">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
|
||||||
|
<div class="col-4 col-md-2">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="gender" class="label">Gender</label>
|
<label for="gender" class="label">Gender</label>
|
||||||
<op-drop-down id="gender" name="gender" [(ngModel)]='data.gender' [source]="GenderOptions">
|
<op-drop-down id="gender" name="gender" [(ngModel)]='data.gender' [source]="GenderOptions">
|
||||||
@ -27,25 +28,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
|
||||||
<div class="form-group">
|
|
||||||
<nb-checkbox id="married" name="married" [(ngModel)]="data.married">Married</nb-checkbox>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-2">
|
|
||||||
<div class="form-group">
|
|
||||||
<nb-checkbox id="baptized" name="baptized" [(ngModel)]="data.baptized">Baptized</nb-checkbox>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-8 col-md-4">
|
||||||
|
<div class='form-group'>
|
||||||
|
<label for='birthday' class='label'>Birthday</label>
|
||||||
|
<op-date-input id='birthday' name='birthday' [(ngModel)]='data.birthday'></op-date-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="email" class="label">Email</label>
|
<label for="email" class="label">Email</label>
|
||||||
<input type="text" name="email" nbInput fullWidth id="email" [(ngModel)]="data.email" readonly>
|
<input type="text" name="email" nbInput fullWidth id="email" [(ngModel)]="data.email" readonly>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="address" class="label">Address</label>
|
<label for="address" class="label">Address</label>
|
||||||
<input type="text" name="address" nbInput fullWidth id="address" [(ngModel)]="data.address">
|
<input type="text" name="address" nbInput fullWidth id="address" [(ngModel)]="data.address">
|
||||||
@ -58,30 +55,30 @@
|
|||||||
[(ngModel)]="data.avatarImage">
|
[(ngModel)]="data.avatarImage">
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div> -->
|
||||||
<div class="col-md-4">
|
|
||||||
<div class='form-group'>
|
|
||||||
<label for='birthday' class='label'>Birthday</label>
|
|
||||||
<input type='text' nbInput fullWidth id='birthday' name='birthday' [(ngModel)]='data.birthday'
|
|
||||||
[nbDatepicker]="dateTimePickerbirthday">
|
|
||||||
<nb-date-timepicker format="yyyy/MM/dd" #dateTimePickerbirthday></nb-date-timepicker>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class='form-group'>
|
|
||||||
<label for='dateOfBaptized' class='label'>Date Of Baptized</label>
|
|
||||||
<input type='text' nbInput fullWidth id='dateOfBaptized' name='dateOfBaptized'
|
|
||||||
[(ngModel)]='data.dateOfBaptized' [nbDatepicker]="dateTimePickerdateOfBaptized">
|
|
||||||
<nb-datepicker format="yyyy/MM/dd" #dateTimePickerdateOfBaptized></nb-datepicker>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-4">
|
<div class="col-6 col-md-2 align-self-md-end">
|
||||||
|
<div class="form-group">
|
||||||
|
<nb-checkbox id="married" name="married" [(ngModel)]="data.married">Married</nb-checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-md-2 align-self-md-end">
|
||||||
|
<div class="form-group">
|
||||||
|
<nb-checkbox id="baptized" name="baptized" [(ngModel)]="data.baptized">Baptized</nb-checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-4">
|
||||||
<div class='form-group'>
|
<div class='form-group'>
|
||||||
<label for='dateOfWalkIn' class='label'>Date Of Walk In</label>
|
<label for='dateOfWalkIn' class='label'>Date Of Walk In</label>
|
||||||
<input type='text' nbInput fullWidth id='dateOfWalkIn' name='dateOfWalkIn'
|
<op-date-input id='dateOfWalkIn' name='dateOfWalkIn' [(ngModel)]='data.dateOfWalkIn'>
|
||||||
[(ngModel)]='data.dateOfWalkIn' [nbDatepicker]="dateTimePickerdateOfWalkIn">
|
</op-date-input>
|
||||||
<nb-date-timepicker format="yyyy/MM/dd" #dateTimePickerdateOfWalkIn></nb-date-timepicker>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-4">
|
||||||
|
<div class='form-group' *ngIf="data.baptized">
|
||||||
|
<label for='dateOfBaptized' class='label'>Date Of Baptized</label>
|
||||||
|
<op-date-input id='dateOfBaptized' name='dateOfBaptized' [(ngModel)]='data.dateOfBaptized'>
|
||||||
|
</op-date-input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -89,10 +86,10 @@
|
|||||||
|
|
||||||
</nb-card-body>
|
</nb-card-body>
|
||||||
<nb-card-footer>
|
<nb-card-footer>
|
||||||
<button class="float-right" nbButton hero status="danger" size="small" (click)="close()"
|
<!-- <button class="float-right" nbButton hero status="danger" size="small" (click)="close()"
|
||||||
[nbSpinner]="processing">
|
[nbSpinner]="processing">
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button> -->
|
||||||
<button class="float-right mr-2" nbButton hero status="primary" size="small"
|
<button class="float-right mr-2" nbButton hero status="primary" size="small"
|
||||||
(click)="!form.invalid&&!processing&&update()" [disabled]="form.invalid" [nbSpinner]="processing">
|
(click)="!form.invalid&&!processing&&update()" [disabled]="form.invalid" [nbSpinner]="processing">
|
||||||
Save
|
Save
|
||||||
|
|||||||
@ -4,22 +4,29 @@ import { AuthService } from '../../services/auth.service';
|
|||||||
import { FamilyMemberService } from '../../services/crudServices/family-member.service';
|
import { FamilyMemberService } from '../../services/crudServices/family-member.service';
|
||||||
import { SessionService } from '../../services/session.service';
|
import { SessionService } from '../../services/session.service';
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
import { DropDownOptions } from '../../entity/dropDownOption';
|
||||||
|
import { NbToastrService } from '@nebular/theme';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ngx-user-profile',
|
selector: 'ngx-user-profile',
|
||||||
templateUrl: './user-profile.component.html',
|
templateUrl: './user-profile.component.html',
|
||||||
styleUrls: ['./user-profile.component.scss']
|
styleUrls: ['./user-profile.component.scss']
|
||||||
})
|
})
|
||||||
export class UserProfileComponent implements OnInit {
|
export class UserProfileComponent implements OnInit {
|
||||||
|
GenderOptions = DropDownOptions.GenderOptions;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private memberService: FamilyMemberService,
|
private memberService: FamilyMemberService,
|
||||||
private authService: AuthService
|
private authService: AuthService,
|
||||||
|
private toastrService: NbToastrService,
|
||||||
) { }
|
) { }
|
||||||
data: FamilyMember;
|
data: FamilyMember;
|
||||||
processing: boolean;
|
processing: boolean;
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.memberService.getById(this.authService.userAccess.memberId).pipe(first()).subscribe(result => {
|
this.memberService.getById(this.authService.userAccess.memberId).pipe(first()).subscribe(result => {
|
||||||
this.data = result;
|
this.data = result;
|
||||||
|
if (this.data.dateOfBaptized == undefined) this.data.dateOfBaptized = null;
|
||||||
|
if (this.data.dateOfWalkIn == undefined) this.data.dateOfWalkIn = null;
|
||||||
|
if (this.data.birthday == undefined) this.data.birthday = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -29,6 +36,7 @@ export class UserProfileComponent implements OnInit {
|
|||||||
update() {
|
update() {
|
||||||
this.memberService.createOrUpdate(this.data).pipe(first()).subscribe(result => {
|
this.memberService.createOrUpdate(this.data).pipe(first()).subscribe(result => {
|
||||||
|
|
||||||
|
this.toastrService.success('更新完成!', '個人資料');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ export interface CellGroupRoutineEvents {
|
|||||||
address: string;
|
address: string;
|
||||||
attendees: CellGroupRoutineEventAttendee[];
|
attendees: CellGroupRoutineEventAttendee[];
|
||||||
prayers: CellGroupRoutineEventPrayer[];
|
prayers: CellGroupRoutineEventPrayer[];
|
||||||
|
pastoralDomainId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { HappinessCost } from "./happiness-cost.model";
|
||||||
import { PastoralDomain } from "./PastoralDomain";
|
import { PastoralDomain } from "./PastoralDomain";
|
||||||
|
|
||||||
export interface HappinessWeek {
|
export interface HappinessWeek {
|
||||||
@ -11,6 +12,7 @@ export interface HappinessWeek {
|
|||||||
seq: number;
|
seq: number;
|
||||||
updateRestWeekDate: boolean;
|
updateRestWeekDate: boolean;
|
||||||
tasks: HappinessTask[];
|
tasks: HappinessTask[];
|
||||||
|
costs: HappinessCost[];
|
||||||
topic: string
|
topic: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { Contribution } from "./contribution.model";
|
||||||
import { HappinessBEST, HappinessWeek } from "./HappinessGroup";
|
import { HappinessBEST, HappinessWeek } from "./HappinessGroup";
|
||||||
import { FamilyMember } from "./Member";
|
import { FamilyMember } from "./Member";
|
||||||
|
|
||||||
@ -6,7 +7,7 @@ export enum DomainType {
|
|||||||
HappinessGroup,
|
HappinessGroup,
|
||||||
CellGroupCoworker,
|
CellGroupCoworker,
|
||||||
ChurchCoworker,
|
ChurchCoworker,
|
||||||
Person = 99
|
Administrator = 99
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PastoralDomain {
|
export interface PastoralDomain {
|
||||||
@ -27,6 +28,7 @@ export interface PastoralDomain {
|
|||||||
|
|
||||||
bests: HappinessBEST[];
|
bests: HappinessBEST[];
|
||||||
happinessWeeks: HappinessWeek[];
|
happinessWeeks: HappinessWeek[];
|
||||||
|
contributions: Contribution[];
|
||||||
|
|
||||||
serviceAddress: AddressInfo;
|
serviceAddress: AddressInfo;
|
||||||
type: DomainType;
|
type: DomainType;
|
||||||
|
|||||||
7
src/app/entity/contribution.model.spec.ts
Normal file
7
src/app/entity/contribution.model.spec.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { Contribution } from './contribution.model';
|
||||||
|
|
||||||
|
describe('Contribution', () => {
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(new Contribution()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
8
src/app/entity/contribution.model.ts
Normal file
8
src/app/entity/contribution.model.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export interface Contribution {
|
||||||
|
groupId: string;
|
||||||
|
id: string;
|
||||||
|
contributor: string;
|
||||||
|
amount: number;
|
||||||
|
comment: string;
|
||||||
|
time: Date;
|
||||||
|
}
|
||||||
7
src/app/entity/happiness-cost.model.spec.ts
Normal file
7
src/app/entity/happiness-cost.model.spec.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { HappinessCost } from './happiness-cost.model';
|
||||||
|
|
||||||
|
describe('HappinessCost', () => {
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(new HappinessCost()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
7
src/app/entity/happiness-cost.model.ts
Normal file
7
src/app/entity/happiness-cost.model.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export class HappinessCost {
|
||||||
|
weekId: string;
|
||||||
|
id: string;
|
||||||
|
tasker: string;
|
||||||
|
content: string;
|
||||||
|
amount: number;
|
||||||
|
}
|
||||||
@ -8,12 +8,12 @@ import * as signalR from "@microsoft/signalr"
|
|||||||
import { StringUtils } from '../../utilities/string-utils';
|
import { StringUtils } from '../../utilities/string-utils';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { MsgBoxService } from '../../services/msg-box.service';
|
import { MsgBoxService } from '../../services/msg-box.service';
|
||||||
import { ADButtons, ADIcon } from '../../ui/alert-dlg/alert-dlg.component';
|
|
||||||
import { UuidUtils } from '../../utilities/uuid-utils';
|
import { UuidUtils } from '../../utilities/uuid-utils';
|
||||||
import { ObjectUtils } from '../../utilities/object-utils';
|
import { ObjectUtils } from '../../utilities/object-utils';
|
||||||
import { NbToastrService } from '@nebular/theme';
|
import { NbToastrService } from '@nebular/theme';
|
||||||
import { AvalonBase } from './avalonBase';
|
import { AvalonBase } from './avalonBase';
|
||||||
import { HeaderService } from '../../services/header.service';
|
import { HeaderService } from '../../services/header.service';
|
||||||
|
import { ADIcon, ADButtons } from '../../ui/alert-dlg/alert-dlg.model';
|
||||||
|
|
||||||
const minimumPlayers = 5;
|
const minimumPlayers = 5;
|
||||||
const maximumPlayers = 10;
|
const maximumPlayers = 10;
|
||||||
@ -181,7 +181,7 @@ export class AvalonComponent extends AvalonBase implements OnInit {
|
|||||||
|
|
||||||
public showMyRole() {
|
public showMyRole() {
|
||||||
let roleInfo = this.getRoleInfoByRole(this.me.role);
|
let roleInfo = this.getRoleInfoByRole(this.me.role);
|
||||||
this.msgBoxService.show(roleInfo.name, roleInfo.description, ADIcon.INFO)
|
this.msgBoxService.show(roleInfo.name, { text: roleInfo.description, icon: ADIcon.INFO });
|
||||||
}
|
}
|
||||||
public showMySecret() {
|
public showMySecret() {
|
||||||
//let roleInfo = this.getRoleInfoByRole(this.me.role);
|
//let roleInfo = this.getRoleInfoByRole(this.me.role);
|
||||||
@ -208,7 +208,7 @@ export class AvalonComponent extends AvalonBase implements OnInit {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.msgBoxService.show('噓...', description, ADIcon.INFO);
|
this.msgBoxService.show('噓...', { text: description, icon: ADIcon.INFO });
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeQuestInfo() {
|
private initializeQuestInfo() {
|
||||||
@ -251,7 +251,7 @@ export class AvalonComponent extends AvalonBase implements OnInit {
|
|||||||
|
|
||||||
previousStage() {
|
previousStage() {
|
||||||
|
|
||||||
this.msgBoxService.show('上一棟', '你確定?', ADIcon.QUESTION, ADButtons.YesNo).pipe(first()).subscribe(result => {
|
this.msgBoxService.show('上一棟', { text: '你確定?', icon: ADIcon.QUESTION, buttons: ADButtons.YesNo }).pipe(first()).subscribe(result => {
|
||||||
if (result) {
|
if (result) {
|
||||||
this.avalonService.data.stage -= 1;
|
this.avalonService.data.stage -= 1;
|
||||||
this.clearVoteStatus();
|
this.clearVoteStatus();
|
||||||
@ -264,14 +264,14 @@ export class AvalonComponent extends AvalonBase implements OnInit {
|
|||||||
switch (this.avalonService.data.stage) {
|
switch (this.avalonService.data.stage) {
|
||||||
case AvalonStage.JoinGame:
|
case AvalonStage.JoinGame:
|
||||||
if (this.players.length < 5) {
|
if (this.players.length < 5) {
|
||||||
this.msgBoxService.show("人數不足!", "遊戲最少需要五人");
|
this.msgBoxService.show("人數不足!", { text: "遊戲最少需要五人" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.gameSize = Math.max(0, this.players.length - 6);
|
this.gameSize = Math.max(0, this.players.length - 6);
|
||||||
|
|
||||||
if (this.avalonService.data.roles.filter(r => r.enabled && false == r.isGood).length != players_evil[this.gameSize]) {
|
if (this.avalonService.data.roles.filter(r => r.enabled && false == r.isGood).length != players_evil[this.gameSize]) {
|
||||||
this.msgBoxService.show("反派人數錯誤!", "反派人數需要 " + players_evil[this.gameSize].toString() + " 人");
|
this.msgBoxService.show("反派人數錯誤!", { text: "反派人數需要 " + players_evil[this.gameSize].toString() + " 人" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { first } from 'rxjs/operators';
|
|||||||
import { GameInfo, Player, Role, RoleInfo } from '../../../entity/Avalon';
|
import { GameInfo, Player, Role, RoleInfo } from '../../../entity/Avalon';
|
||||||
import { AvalonService } from '../../../services/avalon.service';
|
import { AvalonService } from '../../../services/avalon.service';
|
||||||
import { MsgBoxService } from '../../../services/msg-box.service';
|
import { MsgBoxService } from '../../../services/msg-box.service';
|
||||||
import { ADButtons, ADIcon } from '../../../ui/alert-dlg/alert-dlg.component';
|
import { ADButtons, ADIcon } from '../../../ui/alert-dlg/alert-dlg.model';
|
||||||
import { AvalonBase } from '../avalonBase';
|
import { AvalonBase } from '../avalonBase';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -38,7 +38,7 @@ export class ChooseCharacterComponent extends AvalonBase implements OnInit {
|
|||||||
// return;
|
// return;
|
||||||
this.ngZone.run(
|
this.ngZone.run(
|
||||||
_ => {
|
_ => {
|
||||||
this.msgBoxService.show(roleInfo.name, roleInfo.description + '<br>你確定你是?', ADIcon.QUESTION, ADButtons.YesNo).pipe(first()).subscribe(result => {
|
this.msgBoxService.show(roleInfo.name, { text: roleInfo.description + '<br>你確定你是?', icon: ADIcon.QUESTION, buttons: ADButtons.YesNo }).pipe(first()).subscribe(result => {
|
||||||
if (result) {
|
if (result) {
|
||||||
if (this.players.find(p => p.role == roleInfo.role) && roleInfo.role != Role.ArthurKnight) {
|
if (this.players.find(p => p.role == roleInfo.role) && roleInfo.role != Role.ArthurKnight) {
|
||||||
this.toastrService.danger('腳色重複:' + roleInfo.name, '你確定沒有選錯腳色??')
|
this.toastrService.danger('腳色重複:' + roleInfo.name, '你確定沒有選錯腳色??')
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { ChangeDetectorRef, Component, NgZone, OnInit } from '@angular/core';
|
|||||||
import { Player, AvalonStage } from '../../../entity/Avalon';
|
import { Player, AvalonStage } from '../../../entity/Avalon';
|
||||||
import { AvalonService } from '../../../services/avalon.service';
|
import { AvalonService } from '../../../services/avalon.service';
|
||||||
import { MsgBoxService } from '../../../services/msg-box.service';
|
import { MsgBoxService } from '../../../services/msg-box.service';
|
||||||
import { ADIcon } from '../../../ui/alert-dlg/alert-dlg.component';
|
import { ADIcon } from '../../../ui/alert-dlg/alert-dlg.model';
|
||||||
import { AvalonBase } from '../avalonBase';
|
import { AvalonBase } from '../avalonBase';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -38,7 +38,7 @@ export class PickTeammateComponent extends AvalonBase implements OnInit {
|
|||||||
this.avalonService.applyCdChange$.next();
|
this.avalonService.applyCdChange$.next();
|
||||||
} else {
|
} else {
|
||||||
this.ngZone.run(_ => {
|
this.ngZone.run(_ => {
|
||||||
this.msgBoxService.show('任務編組錯誤!', `本次任務出場人數為 ${this.currentQuest.teamSize} 人!`, ADIcon.WARNING);
|
this.msgBoxService.show('任務編組錯誤!', { text: `本次任務出場人數為 ${this.currentQuest.teamSize} 人!`, icon: ADIcon.WARNING });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
|
|||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
import { AvalonComponent } from './avalon/avalon.component';
|
import { AvalonComponent } from './avalon/avalon.component';
|
||||||
import { GamesComponent } from './games.component';
|
import { GamesComponent } from './games.component';
|
||||||
|
import { MassiveDarkness2Component } from './massive-darkness2/massive-darkness2.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
@ -12,6 +13,7 @@ const routes: Routes = [
|
|||||||
[
|
[
|
||||||
{ path: 'avalon', component: AvalonComponent },
|
{ path: 'avalon', component: AvalonComponent },
|
||||||
{ path: 'avalonHost', component: AvalonComponent },
|
{ path: 'avalonHost', component: AvalonComponent },
|
||||||
|
{ path: 'MD2', component: MassiveDarkness2Component },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { TeamVoteComponent } from './avalon/team-vote/team-vote.component';
|
|||||||
import { QuestVoteComponent } from './avalon/quest-vote/quest-vote.component';
|
import { QuestVoteComponent } from './avalon/quest-vote/quest-vote.component';
|
||||||
import { VoteResultComponent } from './avalon/vote-result/vote-result.component';
|
import { VoteResultComponent } from './avalon/vote-result/vote-result.component';
|
||||||
import { QuestTableComponent } from './avalon/quest-table/quest-table.component';
|
import { QuestTableComponent } from './avalon/quest-table/quest-table.component';
|
||||||
|
import { MassiveDarkness2Component } from './massive-darkness2/massive-darkness2.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -28,7 +29,8 @@ import { QuestTableComponent } from './avalon/quest-table/quest-table.component'
|
|||||||
TeamVoteComponent,
|
TeamVoteComponent,
|
||||||
QuestVoteComponent,
|
QuestVoteComponent,
|
||||||
VoteResultComponent,
|
VoteResultComponent,
|
||||||
QuestTableComponent
|
QuestTableComponent,
|
||||||
|
MassiveDarkness2Component
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
|||||||
@ -0,0 +1,25 @@
|
|||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-12 col-md-4">
|
||||||
|
<nb-card>
|
||||||
|
<nb-card-header>
|
||||||
|
Treasure Bag
|
||||||
|
<button nbButton hero status="primary" size="small">Reset</button>
|
||||||
|
<button nbButton hero status="primary" size="small" (click)="addTreasure(TreasureType.Rare)">Add
|
||||||
|
Rare</button>
|
||||||
|
<button nbButton hero status="primary" size="small" (click)="addTreasure(TreasureType.Epic)">Add
|
||||||
|
Epic</button>
|
||||||
|
</nb-card-header>
|
||||||
|
<nb-card-body>
|
||||||
|
<div>
|
||||||
|
<ng-template *ngFor="let treasure of treasureBag.drawingItems">
|
||||||
|
<img src="{{treasure.imageUrl}}"> X {{treasure.unitAmount}}
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
<button nbButton hero status="primary">I feel LUCKY!!!!!</button>
|
||||||
|
</nb-card-body>
|
||||||
|
</nb-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MassiveDarkness2Component } from './massive-darkness2.component';
|
||||||
|
|
||||||
|
describe('MassiveDarkness2Component', () => {
|
||||||
|
let component: MassiveDarkness2Component;
|
||||||
|
let fixture: ComponentFixture<MassiveDarkness2Component>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ MassiveDarkness2Component ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(MassiveDarkness2Component);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
143
src/app/games/massive-darkness2/massive-darkness2.component.ts
Normal file
143
src/app/games/massive-darkness2/massive-darkness2.component.ts
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
||||||
|
import { FileService } from '../../services/file.service';
|
||||||
|
import { MsgBoxService } from '../../services/msg-box.service';
|
||||||
|
import { ArrayUtils } from '../../utilities/array-utils';
|
||||||
|
import { ObjectUtils } from '../../utilities/object-utils';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-massive-darkness2',
|
||||||
|
templateUrl: './massive-darkness2.component.html',
|
||||||
|
styleUrls: ['./massive-darkness2.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class MassiveDarkness2Component implements OnInit {
|
||||||
|
TreasureType = TreasureType;
|
||||||
|
treasureBag: DrawingBag = new DrawingBag();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private fileService: FileService,
|
||||||
|
private cdRef: ChangeDetectorRef,
|
||||||
|
private msgBoxService: MsgBoxService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.resetTreasureBag();
|
||||||
|
this.detectChanges();
|
||||||
|
}
|
||||||
|
detectChanges() {
|
||||||
|
|
||||||
|
if (!this.cdRef['destroyed']) {
|
||||||
|
this.cdRef.detectChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resetTreasureBag() {
|
||||||
|
this.treasureBag.ClearAllItems();
|
||||||
|
this.addTreasure(TreasureType.Common, 15);
|
||||||
|
}
|
||||||
|
addTreasure(type: TreasureType, amount: number = 1) {
|
||||||
|
let item = new DrawingItem(`${TreasureType[type]} Treasure`, `It's a ${TreasureType[type]} Treasure!`, this.fileService.ImageUrl(`TreasureToken/${TreasureType[type]}.png`), amount);
|
||||||
|
|
||||||
|
this.treasureBag.AddItem(item);
|
||||||
|
this.detectChanges();
|
||||||
|
}
|
||||||
|
treasureImage(type: TreasureType) {
|
||||||
|
return this.fileService.ImageUrl(`TreasureToken/${TreasureType[type]}.png`);
|
||||||
|
}
|
||||||
|
drawTreasure() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export enum TreasureType {
|
||||||
|
Common,
|
||||||
|
Rare,
|
||||||
|
Epic,
|
||||||
|
Legendary
|
||||||
|
}
|
||||||
|
export class DrawingBag {
|
||||||
|
constructor() {
|
||||||
|
this.drawingItems = [];
|
||||||
|
this.removedItems = [];
|
||||||
|
}
|
||||||
|
drawingItems: DrawingItem[]
|
||||||
|
removedItems: DrawingItem[]
|
||||||
|
|
||||||
|
public Draw(amount: number): DrawingItem[] {
|
||||||
|
let drawItems: DrawingItem[] = [];
|
||||||
|
for (let i = 0; i < amount; i++) {
|
||||||
|
|
||||||
|
drawItems.push(this.DrawAndRemove());
|
||||||
|
}
|
||||||
|
this.RestoreRemoveItems();
|
||||||
|
return drawItems;
|
||||||
|
}
|
||||||
|
public DrawAndRemove(): DrawingItem {
|
||||||
|
if (this.drawingItems.length > 0) {
|
||||||
|
let drawItem = null as DrawingItem;
|
||||||
|
let drawIndex = Math.random() * this.drawingItems.reduce((sum, current) => sum + current.unitAmount, 0);
|
||||||
|
|
||||||
|
let drawCalc = 0;
|
||||||
|
for (let i = 0; i < this.drawingItems.length; i++) {
|
||||||
|
const item = this.drawingItems[i];
|
||||||
|
drawCalc += item.unitAmount;
|
||||||
|
if (drawCalc >= drawIndex) {
|
||||||
|
drawItem = ObjectUtils.CloneValue(item);
|
||||||
|
drawItem.unitAmount = 1;
|
||||||
|
item.unitAmount -= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//ObjectUtils.CloneValue
|
||||||
|
this.RemoveItem(drawItem);
|
||||||
|
return drawItem;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RestoreRemoveItems() {
|
||||||
|
for (let i = 0; i < this.removedItems.length; i++) {
|
||||||
|
const removedItem = this.removedItems[i];
|
||||||
|
this.AddItem(removedItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public AddItem(item: DrawingItem) {
|
||||||
|
let existingItem = this.drawingItems.find(i => i.name == item.name);
|
||||||
|
if (existingItem) {
|
||||||
|
existingItem.unitAmount += item.unitAmount;
|
||||||
|
} else {
|
||||||
|
this.drawingItems.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemoveItem(item: DrawingItem) {
|
||||||
|
let existingItem = this.removedItems.find(i => i.name == item.name);
|
||||||
|
if (existingItem) {
|
||||||
|
existingItem.unitAmount += item.unitAmount;
|
||||||
|
} else {
|
||||||
|
this.removedItems.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public ClearAllItems() {
|
||||||
|
|
||||||
|
this.drawingItems = [];
|
||||||
|
this.removedItems = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class DrawingItem {
|
||||||
|
constructor(
|
||||||
|
name: string,
|
||||||
|
description: string,
|
||||||
|
imageUrl: string,
|
||||||
|
unitAmount: number = 1
|
||||||
|
) {
|
||||||
|
this.imageUrl = imageUrl
|
||||||
|
this.name = name
|
||||||
|
this.description = description
|
||||||
|
this.unitAmount = unitAmount
|
||||||
|
}
|
||||||
|
imageUrl: string
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
unitAmount: number
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
<form #form="ngForm">
|
||||||
|
<nb-card>
|
||||||
|
<nb-card-header>
|
||||||
|
{{data.name}}
|
||||||
|
</nb-card-header>
|
||||||
|
<nb-card-body>
|
||||||
|
<!-- <loading-spinner [isLoading]="isLoading"></loading-spinner> -->
|
||||||
|
<div class="row" *ngIf="data">
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name" class="label">Name</label>
|
||||||
|
<input type="text" name="name" nbInput fullWidth id="name" [(ngModel)]="data.name">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="phone" class="label">Phone</label>
|
||||||
|
<input type="text" name="phone" nbInput fullWidth id="phone" [(ngModel)]="data.phone">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="email" class="label">Email</label>
|
||||||
|
<input type="text" name="email" nbInput fullWidth id="email" [(ngModel)]="data.email">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</nb-card-body>
|
||||||
|
<nb-card-footer>
|
||||||
|
<button class="float-right" nbButton hero status="danger" size="small" (click)="close()"
|
||||||
|
[nbSpinner]="processing">
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
<button class="float-right mr-2" nbButton hero status="primary" size="small"
|
||||||
|
(click)="!form.invalid&&!processing&&update()" [disabled]="form.invalid" [nbSpinner]="processing">
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</nb-card-footer>
|
||||||
|
</nb-card>
|
||||||
|
</form>
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { BestEditorDlgComponent } from './best-editor-dlg.component';
|
||||||
|
|
||||||
|
describe('BestEditorDlgComponent', () => {
|
||||||
|
let component: BestEditorDlgComponent;
|
||||||
|
let fixture: ComponentFixture<BestEditorDlgComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ BestEditorDlgComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(BestEditorDlgComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { NbDialogRef } from '@nebular/theme';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
import { HappinessBEST } from '../../../entity/HappinessGroup';
|
||||||
|
import { BestService } from '../../../services/crudServices/best.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-best-editor-dlg',
|
||||||
|
templateUrl: './best-editor-dlg.component.html',
|
||||||
|
styleUrls: ['./best-editor-dlg.component.scss']
|
||||||
|
})
|
||||||
|
export class BestEditorDlgComponent implements OnInit {
|
||||||
|
isAdding: boolean = false;
|
||||||
|
processing: boolean = false;
|
||||||
|
data: HappinessBEST;
|
||||||
|
constructor(
|
||||||
|
private bestService: BestService,
|
||||||
|
private dlgRef: NbDialogRef<BestEditorDlgComponent>
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
ngOnInit(): void {
|
||||||
|
if (this.isAdding) {
|
||||||
|
this.data = { id: 'new' } as HappinessBEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.dlgRef.close();
|
||||||
|
}
|
||||||
|
update() {
|
||||||
|
if (this.processing == false) {
|
||||||
|
|
||||||
|
this.processing = true;
|
||||||
|
|
||||||
|
let func = this.bestService.update(this.data);//this.isAdding ? this.bestService.create(this.data) :
|
||||||
|
func.pipe(first()).subscribe(result => {
|
||||||
|
this.processing = false;
|
||||||
|
if (result) {
|
||||||
|
this.dlgRef.close(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,13 @@
|
|||||||
<nb-card>
|
<nb-card [ngClass]="{'isDlg': isDlg}">
|
||||||
<nb-card-header>
|
<nb-card-header>
|
||||||
Happiness Group:{{group.name}} Best List
|
{{group.name}} Best List
|
||||||
<button class="float-right" nbButton hero status="success" size="small" (click)="addBest()"
|
<button class="float-right" nbButton hero status="success" size="small" (click)="addBest()"
|
||||||
[nbSpinner]="processing">Create New</button>
|
[nbSpinner]="processing">Create New</button>
|
||||||
<button class="float-right mr-2" nbButton hero status="success" size="small" (click)="copyBestList()"
|
|
||||||
[nbSpinner]="processing">Copy Whole List</button>
|
<button class="float-right mr-2" nbButton hero status="success" size="small" (click)="pushListToLine()"
|
||||||
|
[nbSpinner]="processing">Push List To Line</button>
|
||||||
|
<!-- <button class="float-right mr-2" nbButton hero status="success" size="small" (click)="copyBestList()"
|
||||||
|
[nbSpinner]="processing">Copy Whole List</button> -->
|
||||||
</nb-card-header>
|
</nb-card-header>
|
||||||
<nb-card-body [nbSpinner]="processing">
|
<nb-card-body [nbSpinner]="processing">
|
||||||
|
|
||||||
@ -24,8 +27,8 @@
|
|||||||
(click)="openEditDlg(best)">Edit</button>
|
(click)="openEditDlg(best)">Edit</button>
|
||||||
<button nbButton hero status="primary" class="mr-1" size="small"
|
<button nbButton hero status="primary" class="mr-1" size="small"
|
||||||
(click)="copyBestUrl(best)">Copy Url</button>
|
(click)="copyBestUrl(best)">Copy Url</button>
|
||||||
<button nbButton hero status="primary" class="" size="small"
|
<button nbButton hero status="primary" class="" size="small" (click)="downloadBestQRCode(best)"
|
||||||
(click)="downloadBestQRCode(best)">QR Code</button>
|
*ngIf="isDlg">QR Code</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
nb-card {
|
||||||
|
max-height: 74vh;
|
||||||
|
.isDlg{
|
||||||
|
max-height: 90vh;
|
||||||
|
width: 700px;
|
||||||
|
}
|
||||||
|
}
|
||||||
108
src/app/happiness/best-list-dlg/best-list-dlg.component.ts
Normal file
108
src/app/happiness/best-list-dlg/best-list-dlg.component.ts
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import { Component, Input, OnInit, Optional } from '@angular/core';
|
||||||
|
import { NbDialogRef, NbDialogService, NbToastrService } from '@nebular/theme';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
import { environment } from '../../../environments/environment';
|
||||||
|
import { HappinessBEST } from '../../entity/HappinessGroup';
|
||||||
|
import { PastoralDomain } from '../../entity/PastoralDomain';
|
||||||
|
import { BestService } from '../../services/crudServices/best.service';
|
||||||
|
import { HappinessGroupService } from '../../services/crudServices/happiness-group.service';
|
||||||
|
import { LineService, LineGroup } from '../../services/line.service';
|
||||||
|
import { MsgBoxService } from '../../services/msg-box.service';
|
||||||
|
import { ADButtons, ADIcon } from '../../ui/alert-dlg/alert-dlg.model';
|
||||||
|
import { ObjectUtils } from '../../utilities/object-utils';
|
||||||
|
import { BestEditorDlgComponent } from './best-editor-dlg/best-editor-dlg.component';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'best-list',
|
||||||
|
templateUrl: './best-list-dlg.component.html',
|
||||||
|
styleUrls: ['./best-list-dlg.component.scss']
|
||||||
|
})
|
||||||
|
export class BestListDlgComponent implements OnInit {
|
||||||
|
|
||||||
|
processing: boolean = false;
|
||||||
|
isAdding: boolean = false;
|
||||||
|
@Input() group: PastoralDomain;
|
||||||
|
datum: HappinessBEST;
|
||||||
|
public get isDlg(): boolean {
|
||||||
|
return this.dlgRef != null;
|
||||||
|
}
|
||||||
|
constructor(
|
||||||
|
private msgBpxService: MsgBoxService,
|
||||||
|
private happinessGroupService: HappinessGroupService,
|
||||||
|
private toastrService: NbToastrService,
|
||||||
|
private bestService: BestService,
|
||||||
|
private lineService: LineService,
|
||||||
|
private dlgService: NbDialogService,
|
||||||
|
@Optional() private dlgRef: NbDialogRef<BestListDlgComponent>,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.group.bests = this.group.bests.sort((a, b) => 0 - (a.name < b.name ? 1 : -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.dlgRef.close();
|
||||||
|
}
|
||||||
|
addBest() {
|
||||||
|
this.msgBpxService.showInputbox('Add Best', 'Please input Best\'s Name').pipe(first()).subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
let obj = { groupId: this.group.id, id: '', name: result } as HappinessBEST;
|
||||||
|
this.bestService.createOrUpdate(obj).pipe(first()).subscribe(result => {
|
||||||
|
this.group.bests.push(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
copyBestUrl(best: HappinessBEST) {
|
||||||
|
|
||||||
|
var dummy = document.createElement("textarea");
|
||||||
|
document.body.appendChild(dummy);
|
||||||
|
dummy.value = `${environment.invitationUrl}${best.id}`;
|
||||||
|
dummy.select();
|
||||||
|
document.execCommand("copy");
|
||||||
|
document.body.removeChild(dummy);
|
||||||
|
this.toastrService.success(dummy.value, "複製地址至剪貼簿!");
|
||||||
|
}
|
||||||
|
copyBestList() {
|
||||||
|
let list = "".concat(...this.group.bests.map(b => `${b.name}\t\t: ${environment.invitationUrl}${b.id}\r\n`));
|
||||||
|
var dummy = document.createElement("textarea");
|
||||||
|
document.body.appendChild(dummy);
|
||||||
|
dummy.value = list;
|
||||||
|
dummy.select();
|
||||||
|
document.execCommand("copy");
|
||||||
|
document.body.removeChild(dummy);
|
||||||
|
this.toastrService.success(dummy.value, "複製地址至剪貼簿!");
|
||||||
|
|
||||||
|
//this.lineService.pushLineMessage(LineGroup.Chris, list);
|
||||||
|
|
||||||
|
}
|
||||||
|
pushListToLine() {
|
||||||
|
this.msgBpxService.show('Push Whole List To Line', { text: 'Are You Sure?', icon: ADIcon.QUESTION, buttons: ADButtons.YesNo }).pipe(first()).subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
this.lineService.pushCommandMessage(this.group.id, 'BEST');
|
||||||
|
this.toastrService.success('Sent', "Sent To Line");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
openEditDlg(best: HappinessBEST) {
|
||||||
|
let isAdding = false;
|
||||||
|
this.dlgService.open(BestEditorDlgComponent, {
|
||||||
|
context: {
|
||||||
|
data: isAdding ? null : ObjectUtils.CloneValue(best),
|
||||||
|
isAdding: isAdding
|
||||||
|
}
|
||||||
|
}).onClose.pipe(first()).subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
ObjectUtils.CopyValue(result, best);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
downloadBestQRCode(best: HappinessBEST) {
|
||||||
|
|
||||||
|
this.happinessGroupService.getBestQrCode(best.name + ".png", best.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,9 +1,8 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { NbDialogRef } from '@nebular/theme';
|
import { NbDialogRef } from '@nebular/theme';
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from 'rxjs/operators';
|
||||||
import { HappinessWeek } from '../../../entity/HappinessGroup';
|
import { HappinessWeek } from '../../entity/HappinessGroup';
|
||||||
import { HappinessGroupService } from '../../../services/crudServices/happiness-group.service';
|
import { HappinessGroupService } from '../../services/crudServices/happiness-group.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ngx-happiness-week-editor',
|
selector: 'ngx-happiness-week-editor',
|
||||||
templateUrl: './happiness-week-editor.component.html',
|
templateUrl: './happiness-week-editor.component.html',
|
||||||
@ -13,6 +12,7 @@ export class HappinessWeekEditorComponent implements OnInit {
|
|||||||
isAdding: boolean = false;
|
isAdding: boolean = false;
|
||||||
processing: boolean = false;
|
processing: boolean = false;
|
||||||
data: HappinessWeek;
|
data: HappinessWeek;
|
||||||
|
allWeeks: HappinessWeek[];
|
||||||
constructor(
|
constructor(
|
||||||
private happinessGroupService: HappinessGroupService,
|
private happinessGroupService: HappinessGroupService,
|
||||||
private dlgRef: NbDialogRef<HappinessWeekEditorComponent>
|
private dlgRef: NbDialogRef<HappinessWeekEditorComponent>
|
||||||
@ -1,25 +1,30 @@
|
|||||||
<nb-card>
|
<nb-card [nbSpinner]="processing">
|
||||||
<nb-card-header>
|
<nb-card-header>
|
||||||
Happiness Group:{{group.name}} Weeks List
|
{{group.name}} 幸福周
|
||||||
|
<button nbButton hero status="primary" class="float-right" size="small" (click)="openTaskDlg(currentWeek)"
|
||||||
|
*ngIf="currentWeek">{{currentWeek.topic}} 分工</button>
|
||||||
</nb-card-header>
|
</nb-card-header>
|
||||||
<nb-card-body>
|
<nb-card-body>
|
||||||
|
|
||||||
<nb-list>
|
<nb-list>
|
||||||
<nb-list-item *ngFor="let week of group.happinessWeeks" class="d-block">
|
<nb-list-item *ngFor="let week of group.happinessWeeks" class="d-block">
|
||||||
<div class="row">
|
<div class="row text-center text-md-left">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
{{weekDisplay(week.seq)}}
|
<p [outerHTML]="weekDisplay(week.seq)"></p>
|
||||||
|
|
||||||
<!-- <nb-user [name]="weekDisplay(week.seq)">
|
<!-- <nb-user [name]="weekDisplay(week.seq)">
|
||||||
</nb-user> -->
|
</nb-user> -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md text-right">
|
<div class="col-md mt-2 mt-md-0 text-md-right">
|
||||||
|
|
||||||
<button nbButton hero status="primary" class="mr-1" size="small"
|
<button nbButton hero status="primary" class="mr-1" size="small"
|
||||||
(click)="openEditDlg(week)">Edit</button>
|
(click)="openEditDlg(week)">Edit</button>
|
||||||
<button nbButton hero status="primary" class="mr-1" size="small"
|
<button nbButton hero status="primary" class="mr-1" size="small"
|
||||||
(click)="openTaskDlg(week)">Tasks</button>
|
(click)="openTaskDlg(week,false)">Tasks</button>
|
||||||
|
<button nbButton hero status="primary" class="mr-1" size="small"
|
||||||
|
(click)="openTaskDlg(week,true)">Costs</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -30,6 +35,7 @@
|
|||||||
|
|
||||||
</nb-card-body>
|
</nb-card-body>
|
||||||
<nb-card-footer>
|
<nb-card-footer>
|
||||||
<button class="float-right" nbButton hero status="danger" size="small" (click)="close()">Close</button>
|
<button class="float-right" nbButton hero status="danger" size="small" (click)="close()"
|
||||||
|
*ngIf="isDlg">Close</button>
|
||||||
</nb-card-footer>
|
</nb-card-footer>
|
||||||
</nb-card>
|
</nb-card>
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
nb-card {
|
||||||
|
max-height: 74vh;
|
||||||
|
width: 615px;
|
||||||
|
max-width: 100vw;
|
||||||
|
.isDlg {
|
||||||
|
max-height: 90vh;
|
||||||
|
width: 700px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,100 @@
|
|||||||
|
import { Component, Input, OnInit, Optional } from '@angular/core';
|
||||||
|
import { NbDialogRef, NbDialogService } from '@nebular/theme';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
import { HappinessWeek } from '../../entity/HappinessGroup';
|
||||||
|
import { PastoralDomain } from '../../entity/PastoralDomain';
|
||||||
|
import { PastoralDomainService } from '../../services/crudServices/pastoral-domain.service';
|
||||||
|
import { NumberUtils } from '../../utilities/number-utils';
|
||||||
|
import { StringUtils } from '../../utilities/string-utils';
|
||||||
|
import { HappinessWeekEditorComponent } from '../happiness-week-editor/happiness-week-editor.component';
|
||||||
|
import { WeekTaskEditorComponent } from '../week-task-editor/week-task-editor.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'happiness-week-list',
|
||||||
|
templateUrl: './happiness-week-list-dlg.component.html',
|
||||||
|
styleUrls: ['./happiness-week-list-dlg.component.scss']
|
||||||
|
})
|
||||||
|
export class HappinessWeekListDlgComponent implements OnInit {
|
||||||
|
|
||||||
|
processing: boolean = false;
|
||||||
|
|
||||||
|
private _group: PastoralDomain;
|
||||||
|
public get group(): PastoralDomain {
|
||||||
|
return this._group;
|
||||||
|
}
|
||||||
|
@Input() public set group(v: PastoralDomain) {
|
||||||
|
if (this._group != v) {
|
||||||
|
this._group = v;
|
||||||
|
this.currentWeek = this.group.happinessWeeks.find(w => w.date >= new Date());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentWeek: HappinessWeek
|
||||||
|
public get isDlg(): boolean {
|
||||||
|
return this.dlgRef != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private dlgService: NbDialogService,
|
||||||
|
private pastoralDomainService: PastoralDomainService,
|
||||||
|
@Optional() private dlgRef: NbDialogRef<any>
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
this.dlgRef.close();
|
||||||
|
}
|
||||||
|
openEditDlg(week: HappinessWeek) {
|
||||||
|
this.dlgService.open(HappinessWeekEditorComponent, {
|
||||||
|
context: {
|
||||||
|
data: week,
|
||||||
|
allWeeks: this.group.happinessWeeks
|
||||||
|
}
|
||||||
|
}).onClose.pipe(first()).subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
if (this.isDlg) {
|
||||||
|
this.close();
|
||||||
|
} else {
|
||||||
|
this.runGetAllData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result) this.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
openTaskDlg(week: HappinessWeek, showingCost: boolean) {
|
||||||
|
this.dlgService.open(WeekTaskEditorComponent, {
|
||||||
|
context: {
|
||||||
|
data: week,
|
||||||
|
showingCost: showingCost,
|
||||||
|
allData: this.group.happinessWeeks
|
||||||
|
}
|
||||||
|
}).onClose.pipe(first()).subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
if (this.isDlg) {
|
||||||
|
this.close();
|
||||||
|
} else {
|
||||||
|
this.runGetAllData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
runGetAllData() {
|
||||||
|
|
||||||
|
this.processing = true;
|
||||||
|
this.pastoralDomainService.initialize().pipe(first()).subscribe(result => {
|
||||||
|
this.group = this.pastoralDomainService.myHappinessGroup;
|
||||||
|
this.processing = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
weekDisplay(seq: number) {
|
||||||
|
let week = this.group.happinessWeeks[seq - 1];
|
||||||
|
let title = `W${seq} ${week.topic}`;
|
||||||
|
let weekCost = week.costs.map(d => d.amount).reduce((a, b) => a + b, 0);
|
||||||
|
if (weekCost > 0) {
|
||||||
|
title += "\t" + StringUtils.getHtmlBadge(`Cost: $${NumberUtils.FormatCurrency(weekCost)}`, 'warning')
|
||||||
|
}
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/app/happiness/happiness.module.ts
Normal file
68
src/app/happiness/happiness.module.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { NbMenuModule, NbInputModule, NbCardModule, NbButtonModule, NbActionsModule, NbCheckboxModule, NbRadioModule, NbDatepickerModule, NbSelectModule, NbIconModule, NbTagModule, NbStepperModule, NbListModule, NbUserModule, NbSpinnerModule, NbDialogModule, NbAlertModule } from '@nebular/theme';
|
||||||
|
import { NgxMaskModule } from 'ngx-mask';
|
||||||
|
import { ThemeModule } from '../@theme/theme.module';
|
||||||
|
import { MaskDirectiveModule } from '../directives/mask-directive/mask-directive.module';
|
||||||
|
import { AlertDlgModule } from '../ui/alert-dlg/alert-dlg.module';
|
||||||
|
import { CurrencyInputModule } from '../ui/currency-input/currency-input.module';
|
||||||
|
import { DateInputModule } from '../ui/date-input/date-input.module';
|
||||||
|
import { DropDownListModule } from '../ui/drop-down-list/drop-down-list.module';
|
||||||
|
import { FancyTableModule } from '../ui/fancy-table/fancy-table.module';
|
||||||
|
import { WeekTaskEditorComponent } from './week-task-editor/week-task-editor.component';
|
||||||
|
import { HappinessWeekEditorComponent } from './happiness-week-editor/happiness-week-editor.component';
|
||||||
|
import { BestListDlgComponent } from './best-list-dlg/best-list-dlg.component';
|
||||||
|
import { HappinessWeekListDlgComponent } from './happiness-week-list-dlg/happiness-week-list-dlg.component';
|
||||||
|
import { BestEditorDlgComponent } from './best-list-dlg/best-editor-dlg/best-editor-dlg.component';
|
||||||
|
import { LoadingSpinnerModule } from '../ui/loading-spinner/loading-spinner.module';
|
||||||
|
import { AddNewCostDlgComponent } from './week-task-editor/add-new-cost-dlg/add-new-cost-dlg.component';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
WeekTaskEditorComponent,
|
||||||
|
HappinessWeekEditorComponent,
|
||||||
|
BestListDlgComponent,
|
||||||
|
HappinessWeekListDlgComponent,
|
||||||
|
BestEditorDlgComponent,
|
||||||
|
AddNewCostDlgComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
FormsModule,
|
||||||
|
ThemeModule,
|
||||||
|
NbMenuModule,
|
||||||
|
NbInputModule,
|
||||||
|
NbCardModule,
|
||||||
|
NbButtonModule,
|
||||||
|
NbActionsModule,
|
||||||
|
NbCheckboxModule,
|
||||||
|
NbRadioModule,
|
||||||
|
NbDatepickerModule,
|
||||||
|
NbSelectModule,
|
||||||
|
NbIconModule,
|
||||||
|
NbTagModule,
|
||||||
|
NbStepperModule,
|
||||||
|
NbListModule,
|
||||||
|
NbUserModule,
|
||||||
|
NbSpinnerModule,
|
||||||
|
NbDialogModule,
|
||||||
|
NbAlertModule,
|
||||||
|
NbSpinnerModule,
|
||||||
|
AlertDlgModule,
|
||||||
|
FancyTableModule,
|
||||||
|
DropDownListModule,
|
||||||
|
NgxMaskModule,
|
||||||
|
CurrencyInputModule,
|
||||||
|
MaskDirectiveModule,
|
||||||
|
DateInputModule,
|
||||||
|
LoadingSpinnerModule
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
BestListDlgComponent,
|
||||||
|
HappinessWeekListDlgComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class HappinessModule { }
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
<nb-card status="success">
|
||||||
|
<nb-card-header>
|
||||||
|
新增開銷
|
||||||
|
</nb-card-header>
|
||||||
|
<nb-card-body>
|
||||||
|
<div class="row form-group">
|
||||||
|
|
||||||
|
<div class="col-6 col-md-4">
|
||||||
|
<div class='form-group'>
|
||||||
|
<label for='costTasker' class='label'>採購人</label>
|
||||||
|
<op-drop-down name="costTasker" [editable]="true" [(ngModel)]="task.tasker" [source]="taskrOptions">
|
||||||
|
</op-drop-down>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-6 col-md-3">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="costAmount" class="label">金額</label>
|
||||||
|
<input type="number" name="costAmount" nbInput fullWidth id="costAmount" [(ngModel)]="task.amount">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-5">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="costContent" class="label">內容</label>
|
||||||
|
<input type="text" name="costContent" nbInput fullWidth id="costContent" [(ngModel)]="task.content">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nb-card-body>
|
||||||
|
<nb-card-footer>
|
||||||
|
<button class="float-right" nbButton hero status="danger" size="small" (click)="close()">Close</button>
|
||||||
|
<button class="float-right mr-2" nbButton hero status="primary" size="small" (click)="submit()">Submit</button>
|
||||||
|
</nb-card-footer>
|
||||||
|
</nb-card>
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AddNewCostDlgComponent } from './add-new-cost-dlg.component';
|
||||||
|
|
||||||
|
describe('AddNewCostDlgComponent', () => {
|
||||||
|
let component: AddNewCostDlgComponent;
|
||||||
|
let fixture: ComponentFixture<AddNewCostDlgComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ AddNewCostDlgComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AddNewCostDlgComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { NbDialogRef } from '@nebular/theme';
|
||||||
|
import { DropDownOption } from '../../../entity/dropDownOption';
|
||||||
|
import { HappinessCost } from '../../../entity/happiness-cost.model';
|
||||||
|
import { AuthService } from '../../../services/auth.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-add-new-cost-dlg',
|
||||||
|
templateUrl: './add-new-cost-dlg.component.html',
|
||||||
|
styleUrls: ['./add-new-cost-dlg.component.scss']
|
||||||
|
})
|
||||||
|
export class AddNewCostDlgComponent implements OnInit {
|
||||||
|
taskrOptions: DropDownOption[] = [];
|
||||||
|
task: HappinessCost;
|
||||||
|
constructor(
|
||||||
|
private authService: AuthService,
|
||||||
|
private dlgRef: NbDialogRef<AddNewCostDlgComponent>
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.task = new HappinessCost();
|
||||||
|
this.task.tasker = this.authService.userAccess.firstName;
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
this.dlgRef.close();
|
||||||
|
}
|
||||||
|
submit() {
|
||||||
|
if (this.task.tasker && this.task.content && this.task.amount > 0) {
|
||||||
|
this.dlgRef.close(this.task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,121 @@
|
|||||||
|
<form #form="ngForm">
|
||||||
|
|
||||||
|
<nb-flip-card [showToggleButton]="false" [flipped]="showingCost">
|
||||||
|
<nb-card-front>
|
||||||
|
<nb-card>
|
||||||
|
<nb-card-header>
|
||||||
|
第 {{data.seq}} 周 {{data.topic}} 分工
|
||||||
|
|
||||||
|
<button class="float-right" nbButton hero status="success" size="small" (click)="toggleView()">
|
||||||
|
Cost
|
||||||
|
</button>
|
||||||
|
</nb-card-header>
|
||||||
|
<nb-card-body *ngIf="data">
|
||||||
|
<div class="row" *ngFor="let task of data.tasks;let i = index">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class='form-group'>
|
||||||
|
<label for='tasker{{i}}' class='label'>{{getTaskTitle(task.type)}}</label>
|
||||||
|
<op-drop-down name="tasker{{i}}" [editable]="true" [(ngModel)]="task.tasker"
|
||||||
|
[source]="taskrOptions">
|
||||||
|
</op-drop-down>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="content{{i}}" class="label">內容</label>
|
||||||
|
<input type="text" name="content{{i}}" nbInput fullWidth id="content{{i}}"
|
||||||
|
[(ngModel)]="task.content">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</nb-card-body>
|
||||||
|
<nb-card-footer>
|
||||||
|
<button class="mr-2" nbButton hero status="info" size="small" (click)="gotoPreviousWeek()"
|
||||||
|
[nbSpinner]="processing">
|
||||||
|
Previous
|
||||||
|
</button>
|
||||||
|
<button nbButton hero status="info" size="small" (click)="gotoNextWeek()" [nbSpinner]="processing">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
<button class="float-right" nbButton hero status="danger" size="small" (click)="close()"
|
||||||
|
[nbSpinner]="processing">
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
<button class="float-right mr-2" nbButton hero status="primary" size="small"
|
||||||
|
(click)="!form.invalid&&!processing&&update()" [disabled]="form.invalid"
|
||||||
|
[nbSpinner]="processing">
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</nb-card-footer>
|
||||||
|
</nb-card>
|
||||||
|
</nb-card-front>
|
||||||
|
<nb-card-back>
|
||||||
|
<nb-card>
|
||||||
|
<nb-card-header>
|
||||||
|
第 {{data.seq}} 周 {{data.topic}} 開銷
|
||||||
|
|
||||||
|
<button class="float-right" nbButton hero status="success" size="small" (click)="toggleView()">
|
||||||
|
分工
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="float-right mr-1" nbButton hero status="success" size="small" (click)="addNewCost()">
|
||||||
|
新增開銷
|
||||||
|
</button>
|
||||||
|
</nb-card-header>
|
||||||
|
<nb-card-body *ngIf="data">
|
||||||
|
<div class="row" *ngFor="let task of data.costs;let i = index">
|
||||||
|
<div class="col-6 col-md-4">
|
||||||
|
<div class='form-group'>
|
||||||
|
<label for='costTasker{{i}}' class='label'>採購人</label>
|
||||||
|
<op-drop-down name="costTasker{{i}}" [editable]="true" [(ngModel)]="task.tasker"
|
||||||
|
[source]="taskrOptions">
|
||||||
|
</op-drop-down>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-6 col-md-3">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="costAmount{{i}}" class="label">金額</label>
|
||||||
|
<input type="number" name="costAmount{{i}}" nbInput fullWidth id="costAmount{{i}}"
|
||||||
|
[(ngModel)]="task.amount">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-5">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="costContent{{i}}" class="label">內容</label>
|
||||||
|
<input type="text" name="costContent{{i}}" nbInput fullWidth id="costContent{{i}}"
|
||||||
|
[(ngModel)]="task.content">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nb-alert status="primary" *ngIf="data.costs.length==0">
|
||||||
|
本周暫無開銷
|
||||||
|
</nb-alert>
|
||||||
|
|
||||||
|
</nb-card-body>
|
||||||
|
<nb-card-footer>
|
||||||
|
|
||||||
|
<button class="mr-2" nbButton hero status="info" size="small" (click)="gotoPreviousWeek()"
|
||||||
|
[nbSpinner]="processing">
|
||||||
|
Previous
|
||||||
|
</button>
|
||||||
|
<button nbButton hero status="info" size="small" (click)="gotoNextWeek()" [nbSpinner]="processing">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
<button class="float-right" nbButton hero status="danger" size="small" (click)="close()"
|
||||||
|
[nbSpinner]="processing">
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
<button class="float-right mr-2" nbButton hero status="primary" size="small"
|
||||||
|
(click)="!processing&&updateCost()" [nbSpinner]="processing">
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</nb-card-footer>
|
||||||
|
</nb-card>
|
||||||
|
</nb-card-back>
|
||||||
|
</nb-flip-card>
|
||||||
|
|
||||||
|
</form>
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
nb-flip-card{
|
||||||
|
max-width: 88vw;
|
||||||
|
}
|
||||||
129
src/app/happiness/week-task-editor/week-task-editor.component.ts
Normal file
129
src/app/happiness/week-task-editor/week-task-editor.component.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
||||||
|
import { NbDialogRef, NbDialogService, NbToastrService } from '@nebular/theme';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
import { DropDownOption } from '../../entity/dropDownOption';
|
||||||
|
import { HappinessCost } from '../../entity/happiness-cost.model';
|
||||||
|
import { HappinessWeek, HappinessTaskType, HappinessTask } from '../../entity/HappinessGroup';
|
||||||
|
import { HappinessCostService } from '../../services/crudServices/happiness-cost.service';
|
||||||
|
import { HappinessTaskService } from '../../services/crudServices/happiness-group.service';
|
||||||
|
import { StringUtils } from '../../utilities/string-utils';
|
||||||
|
import { AddNewCostDlgComponent } from './add-new-cost-dlg/add-new-cost-dlg.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-week-task-editor',
|
||||||
|
templateUrl: './week-task-editor.component.html',
|
||||||
|
styleUrls: ['./week-task-editor.component.scss']
|
||||||
|
})
|
||||||
|
export class WeekTaskEditorComponent implements OnInit {
|
||||||
|
processing: boolean = false;
|
||||||
|
allData: HappinessWeek[];
|
||||||
|
data: HappinessWeek;
|
||||||
|
taskrOptions: DropDownOption[] = [];
|
||||||
|
showingCost: boolean = false;
|
||||||
|
constructor(
|
||||||
|
private happinessTaskService: HappinessTaskService,
|
||||||
|
private happinessCostService: HappinessCostService,
|
||||||
|
private dlgRef: NbDialogRef<WeekTaskEditorComponent>,
|
||||||
|
private dlgService: NbDialogService,
|
||||||
|
private toastrService: NbToastrService,
|
||||||
|
private cdRef: ChangeDetectorRef
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
ngOnInit(): void {
|
||||||
|
if (this.data.tasks.length == 0) {
|
||||||
|
this.data.tasks = [];
|
||||||
|
for (let i = HappinessTaskType.IceBreak; i <= HappinessTaskType.Dessert; i++) {
|
||||||
|
this.data.tasks.push(
|
||||||
|
{
|
||||||
|
weekId: this.data.id,
|
||||||
|
id: 'new',
|
||||||
|
type: i as HappinessTaskType,
|
||||||
|
tasker: '',
|
||||||
|
content: ''
|
||||||
|
} as HappinessTask
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let names = [] as string[];
|
||||||
|
this.allData.forEach(week => {
|
||||||
|
if (week.tasks) {
|
||||||
|
names = names.concat(week.tasks.map(t => t.tasker ? t.tasker.trim() : ''));
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.taskrOptions = names.filter(function (item, pos) {
|
||||||
|
return !StringUtils.isNullOrWhitespace(item) && names.indexOf(item) == pos;
|
||||||
|
}).map(name => new DropDownOption(name, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.dlgRef.close();
|
||||||
|
}
|
||||||
|
update() {
|
||||||
|
if (this.processing == false) {
|
||||||
|
|
||||||
|
this.processing = true;
|
||||||
|
|
||||||
|
this.happinessTaskService.createOrUpdateAll(this.data.tasks).pipe(first()).subscribe(result => {
|
||||||
|
this.processing = false;
|
||||||
|
this.toastrService.success("Update Success!");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCost() {
|
||||||
|
if (this.processing == false) {
|
||||||
|
|
||||||
|
this.processing = true;
|
||||||
|
|
||||||
|
this.happinessCostService.createOrUpdateAll(this.data.costs).pipe(first()).subscribe(result => {
|
||||||
|
this.processing = false;
|
||||||
|
this.toastrService.success("Update Cost Success!");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
getTaskTitle(t: HappinessTaskType) {
|
||||||
|
switch (t) {
|
||||||
|
case HappinessTaskType.IceBreak: return '帶遊戲';
|
||||||
|
case HappinessTaskType.Worship: return '唱歌';
|
||||||
|
case HappinessTaskType.Testimony: return '見證';
|
||||||
|
case HappinessTaskType.Message: return '信息';
|
||||||
|
case HappinessTaskType.Gift: return '準備禮物';
|
||||||
|
case HappinessTaskType.Dessert: return '準備點心';
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleView() {
|
||||||
|
this.showingCost = !this.showingCost;
|
||||||
|
}
|
||||||
|
addNewCost() {
|
||||||
|
this.dlgService.open(AddNewCostDlgComponent, {
|
||||||
|
context: {
|
||||||
|
taskrOptions: this.taskrOptions
|
||||||
|
}
|
||||||
|
}).onClose.pipe(first()).subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
result.weekId = this.data.id;
|
||||||
|
this.happinessCostService.createOrUpdate(result).pipe(first()).subscribe(result => {
|
||||||
|
this.data.costs.push(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
gotoNextWeek() {
|
||||||
|
if ((this.allData.indexOf(this.data) + 1) < this.allData.length) {
|
||||||
|
this.data = this.allData[this.allData.indexOf(this.data) + 1];
|
||||||
|
this.cdRef.detectChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gotoPreviousWeek() {
|
||||||
|
if ((this.allData.indexOf(this.data) - 1) >= 0) {
|
||||||
|
this.data = this.allData[this.allData.indexOf(this.data) - 1];
|
||||||
|
this.cdRef.detectChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,7 @@
|
|||||||
data-header-fix-moment-classes="light-theme u-theme-shadow-v1 g-bg-white g-py-5--md">
|
data-header-fix-moment-classes="light-theme u-theme-shadow-v1 g-bg-white g-py-5--md">
|
||||||
<nav class="navbar navbar-expand-lg p-0 g-px-15">
|
<nav class="navbar navbar-expand-lg p-0 g-px-15">
|
||||||
<div class="mx-auto">
|
<div class="mx-auto">
|
||||||
<a href="/CellGroup/prayer" class="g-hidden-lg-up navbar-brand mr-0">
|
<a href="/myapp" class="g-hidden-lg-up navbar-brand mr-0">
|
||||||
<img class="d-block g-height-50 g-height-60--md" src="/assets/home/images/logo-light.png"
|
<img class="d-block g-height-50 g-height-60--md" src="/assets/home/images/logo-light.png"
|
||||||
alt="Image Description" data-header-fix-moment-exclude="d-block"
|
alt="Image Description" data-header-fix-moment-exclude="d-block"
|
||||||
data-header-fix-moment-classes="d-none">
|
data-header-fix-moment-classes="d-none">
|
||||||
@ -29,7 +29,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<!-- Logo -->
|
<!-- Logo -->
|
||||||
<li class="g-hidden-lg-down nav-logo-item g-mx-15--lg">
|
<li class="g-hidden-lg-down nav-logo-item g-mx-15--lg">
|
||||||
<a href="#hometop" class="js-go-to navbar-brand mr-0" data-type="static">
|
<a href="/myapp" class="js-go-to navbar-brand mr-0" data-type="static">
|
||||||
<img class="d-block g-height-50 g-height-60--md"
|
<img class="d-block g-height-50 g-height-60--md"
|
||||||
src="/assets/home/images/logo-light.png" alt="Image Description"
|
src="/assets/home/images/logo-light.png" alt="Image Description"
|
||||||
data-header-fix-moment-exclude="d-block" data-header-fix-moment-classes="d-none">
|
data-header-fix-moment-exclude="d-block" data-header-fix-moment-classes="d-none">
|
||||||
|
|||||||
@ -155,10 +155,11 @@ export class InvitationComponent implements OnInit {
|
|||||||
.type('這周想邀請你一起來度過一個輕鬆舒壓的夜晚!')
|
.type('這周想邀請你一起來度過一個輕鬆舒壓的夜晚!')
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
instance.type(`Hi, <strong>${this.best.name}</strong>,<br>`)
|
instance.type(`Hi, 親愛的<strong>${this.best.name}</strong>,<br>`)
|
||||||
.type('你有多久沒有和家人朋友一同野餐了呢?<br>')
|
.type('經歷了這幾週的幸福之旅,<br>')
|
||||||
.type('這周六想邀請你與我們沐浴陽光,因為<b>天父爸爸</b>說:')
|
.type('在這週我們想要邀請你來更認識我們充滿愛的 <strong>家</strong>,<br> ')
|
||||||
.options({ speed: 350 }).type('<h3>歡迎回家!</h3>')
|
.type('和我們度過一段溫馨的家庭聚會時光, <br>')
|
||||||
|
.type('感受屬於家的溫暖和幸福!')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { Subject } from 'rxjs';
|
|||||||
import { first, takeUntil } from 'rxjs/operators';
|
import { first, takeUntil } from 'rxjs/operators';
|
||||||
import { LoginTokenViewModel, RegisterViewModel } from '../entity/Auth';
|
import { LoginTokenViewModel, RegisterViewModel } from '../entity/Auth';
|
||||||
import { AuthService } from '../services/auth.service';
|
import { AuthService } from '../services/auth.service';
|
||||||
|
import { PastoralDomainService } from '../services/crudServices/pastoral-domain.service';
|
||||||
import { SessionService } from '../services/session.service';
|
import { SessionService } from '../services/session.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -40,7 +41,9 @@ export class LoginComponent {
|
|||||||
protected router: Router,
|
protected router: Router,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private sessionService: SessionService,
|
private sessionService: SessionService,
|
||||||
private authService: AuthService) {
|
private authService: AuthService,
|
||||||
|
private pastoralDomainService: PastoralDomainService
|
||||||
|
) {
|
||||||
|
|
||||||
this.redirectDelay = this.getConfigValue('forms.login.redirectDelay');
|
this.redirectDelay = this.getConfigValue('forms.login.redirectDelay');
|
||||||
this.showMessages = this.getConfigValue('forms.login.showMessages');
|
this.showMessages = this.getConfigValue('forms.login.showMessages');
|
||||||
@ -94,11 +97,13 @@ export class LoginComponent {
|
|||||||
|
|
||||||
if (result && result.token) {
|
if (result && result.token) {
|
||||||
|
|
||||||
|
this.pastoralDomainService.initialize().pipe(first()).subscribe(result => {
|
||||||
if (this.sessionService.redirectAfterLogin) {
|
if (this.sessionService.redirectAfterLogin) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
return this.router.navigateByUrl(this.sessionService.redirectAfterLogin);
|
return this.router.navigateByUrl(this.sessionService.redirectAfterLogin);
|
||||||
}, this.redirectDelay);
|
}, this.redirectDelay);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.errors = ['Invalid Credential.'];
|
this.errors = ['Invalid Credential.'];
|
||||||
}
|
}
|
||||||
@ -124,7 +129,9 @@ export class LoginComponent {
|
|||||||
this.authService.loginWithGoogleAccessToken(authResult.getToken().getValue())
|
this.authService.loginWithGoogleAccessToken(authResult.getToken().getValue())
|
||||||
.pipe(first()).subscribe(result => {
|
.pipe(first()).subscribe(result => {
|
||||||
if (result) {
|
if (result) {
|
||||||
|
this.pastoralDomainService.initialize().pipe(first()).subscribe(result => {
|
||||||
this.redirect();
|
this.redirect();
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.isCallback = false;
|
this.isCallback = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,7 +79,9 @@ export class ApiPrefixInterceptor implements HttpInterceptor {
|
|||||||
if (value instanceof Object) {
|
if (value instanceof Object) {
|
||||||
this.convertDates(value);
|
this.convertDates(value);
|
||||||
}
|
}
|
||||||
if (typeof value === 'string' &&
|
if (
|
||||||
|
(typeof value === 'string' || typeof value === 'undefined')
|
||||||
|
&&
|
||||||
(key.toLowerCase().indexOf('date') > -1 || key.toLowerCase().indexOf('time') > -1 || key.toLowerCase().indexOf('birthday') > -1)
|
(key.toLowerCase().indexOf('date') > -1 || key.toLowerCase().indexOf('time') > -1 || key.toLowerCase().indexOf('birthday') > -1)
|
||||||
) {
|
) {
|
||||||
//object[key] = new Date(value.replace('+00:00', ' UTC'));
|
//object[key] = new Date(value.replace('+00:00', ' UTC'));
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { Observable } from 'rxjs';
|
|||||||
import { map, mergeMap, first } from 'rxjs/operators';
|
import { map, mergeMap, first } from 'rxjs/operators';
|
||||||
import { environment } from '../../environments/environment';
|
import { environment } from '../../environments/environment';
|
||||||
import { GoogleUserInfo, LoginTokenViewModel, RegisterViewModel } from '../entity/Auth';
|
import { GoogleUserInfo, LoginTokenViewModel, RegisterViewModel } from '../entity/Auth';
|
||||||
|
import { PastoralDomainService } from './crudServices/pastoral-domain.service';
|
||||||
import { SessionService } from './session.service';
|
import { SessionService } from './session.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@ -20,12 +21,13 @@ export class AuthService {
|
|||||||
private sessionService: SessionService,
|
private sessionService: SessionService,
|
||||||
private oAuthService: NbAuthService,
|
private oAuthService: NbAuthService,
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
|
private pastoralDomainService: PastoralDomainService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
logout() {
|
logout() {
|
||||||
this.sessionService.loginUserToken = '';
|
this.sessionService.loginUserToken = '';
|
||||||
this.userAccess = {} as LoginTokenViewModel;
|
this.userAccess = {} as LoginTokenViewModel;
|
||||||
|
this.pastoralDomainService.domains = [];
|
||||||
this.oAuthService.getToken().pipe(first()).subscribe(result => {
|
this.oAuthService.getToken().pipe(first()).subscribe(result => {
|
||||||
console.log('logoutToken', result);
|
console.log('logoutToken', result);
|
||||||
if (result.isValid() && result.getOwnerStrategyName()) {
|
if (result.isValid() && result.getOwnerStrategyName()) {
|
||||||
@ -48,6 +50,11 @@ export class AuthService {
|
|||||||
return this.loginWithToken(this.sessionService.loginUserToken).pipe(map(result => {
|
return this.loginWithToken(this.sessionService.loginUserToken).pipe(map(result => {
|
||||||
if (!result) {
|
if (!result) {
|
||||||
this.sessionService.loginUserToken = "";
|
this.sessionService.loginUserToken = "";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
this.pastoralDomainService.initialize().pipe(first()).subscribe(result => {
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}));;
|
}));;
|
||||||
@ -66,7 +73,7 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private headerObj = new HttpHeaders({ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36' })
|
private headerObj = new HttpHeaders({ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36' })
|
||||||
loginWithGoogleAccessToken(googleToken) {
|
loginWithGoogleAccessToken(googleToken): Observable<LoginTokenViewModel> {
|
||||||
|
|
||||||
return this.post('auth/oauth-login',
|
return this.post('auth/oauth-login',
|
||||||
{
|
{
|
||||||
@ -75,26 +82,26 @@ export class AuthService {
|
|||||||
} as RegisterViewModel,
|
} as RegisterViewModel,
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.http.get(`https://www.googleapis.com/oauth2/v2/userinfo?access_token=${googleToken}`, {
|
// return this.http.get(`https://www.googleapis.com/oauth2/v2/userinfo?access_token=${googleToken}`, {
|
||||||
headers: this.headerObj
|
// headers: this.headerObj
|
||||||
})
|
// })
|
||||||
.pipe(
|
// .pipe(
|
||||||
map(googleUserInfo => { return googleUserInfo as GoogleUserInfo }),
|
// map(googleUserInfo => { return googleUserInfo as GoogleUserInfo }),
|
||||||
mergeMap(
|
// mergeMap(
|
||||||
googleUserInfo => {
|
// googleUserInfo => {
|
||||||
if (!googleUserInfo.error) {
|
// if (!googleUserInfo.error) {
|
||||||
|
|
||||||
return this.post('auth/sign-up',
|
// return this.post('auth/sign-up',
|
||||||
{
|
// {
|
||||||
email: googleUserInfo.email,
|
// email: googleUserInfo.email,
|
||||||
fistName: googleUserInfo.given_name,
|
// fistName: googleUserInfo.given_name,
|
||||||
lastName: googleUserInfo.family_name,
|
// lastName: googleUserInfo.family_name,
|
||||||
avatarImage: googleUserInfo.picture
|
// avatarImage: googleUserInfo.picture
|
||||||
} as RegisterViewModel,
|
// } as RegisterViewModel,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
return Observable.of(null);
|
// return Observable.of(null);
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,6 +161,7 @@ export class AuthService {
|
|||||||
if (result && result.token) {
|
if (result && result.token) {
|
||||||
this.userAccess = result;
|
this.userAccess = result;
|
||||||
this.sessionService.loginUserToken = result.token;
|
this.sessionService.loginUserToken = result.token;
|
||||||
|
this.sessionService.loginUserId = result.memberId;
|
||||||
} else {
|
} else {
|
||||||
this.userAccess = {} as LoginTokenViewModel;
|
this.userAccess = {} as LoginTokenViewModel;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,21 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
import { PastoralDomain } from '../../entity/PastoralDomain';
|
||||||
|
import { PastoralDomainService } from './pastoral-domain.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class CellGroupService {
|
export class CellGroupService {
|
||||||
|
|
||||||
constructor() { }
|
cellGroup: PastoralDomain = null;
|
||||||
|
constructor(private pastoralDomainService: PastoralDomainService) {
|
||||||
|
|
||||||
|
}
|
||||||
|
initialize() {
|
||||||
|
return this.pastoralDomainService.getCurrentUserPastoralDomain().pipe(map(result => {
|
||||||
|
this.cellGroup
|
||||||
|
return result;
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/app/services/crudServices/contribution.service.spec.ts
Normal file
16
src/app/services/crudServices/contribution.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ContributionService } from './contribution.service';
|
||||||
|
|
||||||
|
describe('ContributionService', () => {
|
||||||
|
let service: ContributionService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(ContributionService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
19
src/app/services/crudServices/contribution.service.ts
Normal file
19
src/app/services/crudServices/contribution.service.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { CrudService } from './crud.service';
|
||||||
|
import { first, map } from 'rxjs/operators';
|
||||||
|
import { Contribution } from '../../entity/contribution.model';
|
||||||
|
|
||||||
|
const BASE_URL = (action: string = null) => { return `Contribution${(action ? `/${action}` : '')}` }
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ContributionService extends CrudService<Contribution> {
|
||||||
|
|
||||||
|
constructor(protected http: HttpClient) {
|
||||||
|
super(http, BASE_URL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -11,8 +11,8 @@ export interface ICrudService<T> {
|
|||||||
getAll(): Observable<T[]>
|
getAll(): Observable<T[]>
|
||||||
getById(id: any): Observable<T>;
|
getById(id: any): Observable<T>;
|
||||||
update(data: T): Observable<boolean>;
|
update(data: T): Observable<boolean>;
|
||||||
createOrUpdate(data: T): Observable<boolean>;
|
createOrUpdate(data: T): Observable<T>;
|
||||||
createOrUpdateAll(data: T[]): Observable<boolean>;
|
createOrUpdateAll(data: T[]): Observable<T[]>;
|
||||||
delete(id: any): Observable<T>;
|
delete(id: any): Observable<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ export class CrudService<T> implements ICrudService<T> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
createOrUpdate(data: T) {
|
createOrUpdate(data: T) {
|
||||||
return this.http.post<boolean>(this.POST_URL_CREATE_OR_UPDATE(),
|
return this.http.post<T>(this.POST_URL_CREATE_OR_UPDATE(),
|
||||||
JSON.stringify(data), {
|
JSON.stringify(data), {
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
@ -61,7 +61,7 @@ export class CrudService<T> implements ICrudService<T> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
createOrUpdateAll(data: T[]) {
|
createOrUpdateAll(data: T[]) {
|
||||||
return this.http.post<boolean>(this.POST_URL_CREATE_OR_UPDATE_ALL(),
|
return this.http.post<T[]>(this.POST_URL_CREATE_OR_UPDATE_ALL(),
|
||||||
JSON.stringify(data), {
|
JSON.stringify(data), {
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
@ -133,7 +133,7 @@ export class CombinedKeyCrudService<T> implements ICrudService<T> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
createOrUpdate(data: T) {
|
createOrUpdate(data: T) {
|
||||||
return this.http.post<boolean>(this.POST_URL_CREATE_OR_UPDATE(),
|
return this.http.post<T>(this.POST_URL_CREATE_OR_UPDATE(),
|
||||||
JSON.stringify(data), {
|
JSON.stringify(data), {
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
@ -143,7 +143,7 @@ export class CombinedKeyCrudService<T> implements ICrudService<T> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
createOrUpdateAll(data: T[]) {
|
createOrUpdateAll(data: T[]) {
|
||||||
return this.http.post<boolean>(this.POST_URL_CREATE_OR_UPDATE_ALL(),
|
return this.http.post<T[]>(this.POST_URL_CREATE_OR_UPDATE_ALL(),
|
||||||
JSON.stringify(data), {
|
JSON.stringify(data), {
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DomainMemberShipService } from './domain-member-ship.service';
|
||||||
|
|
||||||
|
describe('DomainMemberShipService', () => {
|
||||||
|
let service: DomainMemberShipService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(DomainMemberShipService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
52
src/app/services/crudServices/domain-member-ship.service.ts
Normal file
52
src/app/services/crudServices/domain-member-ship.service.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { NewVisitor } from '../../entity/NewVisitor';
|
||||||
|
import { CrudService } from './crud.service';
|
||||||
|
import { first, map } from 'rxjs/operators';
|
||||||
|
import { DomainMemberRelationship } from '../../entity/PastoralDomain';
|
||||||
|
|
||||||
|
const BASE_URL = (action: string = null) => { return `DomainMemberShip${(action ? `/${action}` : '')}` }
|
||||||
|
const POST_URL_ASSIGN_CELL_GROUPS = 'DomainMemberShip/AssignCellGroups'
|
||||||
|
const GET_URL_ADD_MEMBER_INTO_GROUP = (domainId, memberId) => `DomainMemberShip/AddMemberIntoGroup?domainId=${domainId}&memberId=${memberId}`;
|
||||||
|
const GET_URL_REMOVE_MEMBER_FROM_GROUP = (domainId, memberId) => `DomainMemberShip/RemoveMemberFromGroup?domainId=${domainId}&memberId=${memberId}`;
|
||||||
|
const POST_URL_UPDATE_MEMBERS_IN_GROUP = 'DomainMemberShip/UpdateMembersInGroup'
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class DomainMemberShipService extends CrudService<DomainMemberRelationship> {
|
||||||
|
|
||||||
|
constructor(protected http: HttpClient) {
|
||||||
|
super(http, BASE_URL);
|
||||||
|
}
|
||||||
|
assignCellGroups(data) {
|
||||||
|
return this.http.post<boolean>(POST_URL_ASSIGN_CELL_GROUPS,
|
||||||
|
JSON.stringify(data), {
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
addMemberIntoGroup(domainId: string, memberId: string) {
|
||||||
|
return this.http.get<number>(GET_URL_ADD_MEMBER_INTO_GROUP(domainId, memberId));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeMemberFromGroup(domainId: string, memberId: string) {
|
||||||
|
return this.http.get<number>(GET_URL_REMOVE_MEMBER_FROM_GROUP(domainId, memberId));
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMembersInGroup(data) {
|
||||||
|
return this.http.post<boolean>(POST_URL_UPDATE_MEMBERS_IN_GROUP,
|
||||||
|
JSON.stringify(data), {
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
src/app/services/crudServices/happiness-cost.service.spec.ts
Normal file
16
src/app/services/crudServices/happiness-cost.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { HappinessCostService } from './happiness-cost.service';
|
||||||
|
|
||||||
|
describe('HappinessCostService', () => {
|
||||||
|
let service: HappinessCostService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(HappinessCostService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
19
src/app/services/crudServices/happiness-cost.service.ts
Normal file
19
src/app/services/crudServices/happiness-cost.service.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { CrudService } from './crud.service';
|
||||||
|
import { first, map } from 'rxjs/operators';
|
||||||
|
import { HappinessCost } from '../../entity/happiness-cost.model';
|
||||||
|
|
||||||
|
const BASE_URL = (action: string = null) => { return `HappinessCost${(action ? `/${action}` : '')}` }
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class HappinessCostService extends CrudService<HappinessCost> {
|
||||||
|
|
||||||
|
constructor(protected http: HttpClient) {
|
||||||
|
super(http, BASE_URL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,40 +1,66 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { DomainMemberRelationship, PastoralDomain } from '../../entity/PastoralDomain';
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
|
import { map, mergeMap } from 'rxjs/operators';
|
||||||
|
import { DomainMemberRelationship, DomainType, PastoralDomain } from '../../entity/PastoralDomain';
|
||||||
|
import { AuthService } from '../auth.service';
|
||||||
|
import { SessionService } from '../session.service';
|
||||||
import { CombinedKeyCrudService, CrudService } from './crud.service';
|
import { CombinedKeyCrudService, CrudService } from './crud.service';
|
||||||
|
import { DomainMemberShipService } from './domain-member-ship.service';
|
||||||
|
|
||||||
const BASE_URL = (action: string = null) => { return `PastoralDomain${(action ? `/${action}` : '')}` }
|
const BASE_URL = (action: string = null) => { return `PastoralDomain${(action ? `/${action}` : '')}` }
|
||||||
|
|
||||||
const RELATIONSHIP_BASE_URL = (action: string = null) => { return `DomainMemberShip${(action ? `/${action}` : '')}` }
|
const RELATIONSHIP_BASE_URL = (action: string = null) => { return `DomainMemberShip${(action ? `/${action}` : '')}` }
|
||||||
const POST_URL_ASSIGN_CELL_GROUPS = 'DomainMemberShip/AssignCellGroups'
|
const POST_URL_ASSIGN_CELL_GROUPS = 'DomainMemberShip/AssignCellGroups'
|
||||||
|
const GET_URL_GET_CURRENT_USER_PASTORAL_DOMAIN = `PastoralDomain/GetCurrentUserPastoralDomain`;
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class PastoralDomainService extends CrudService<PastoralDomain> {
|
export class PastoralDomainService extends CrudService<PastoralDomain> {
|
||||||
|
|
||||||
constructor(protected http: HttpClient) {
|
initialized = new BehaviorSubject<boolean>(false);
|
||||||
|
domains: PastoralDomain[] = [];
|
||||||
|
constructor(
|
||||||
|
protected http: HttpClient,
|
||||||
|
private domainMemberShipService: DomainMemberShipService,
|
||||||
|
private session: SessionService
|
||||||
|
) {
|
||||||
super(http, BASE_URL);
|
super(http, BASE_URL);
|
||||||
}
|
}
|
||||||
}
|
getCurrentUserPastoralDomain() {
|
||||||
|
return this.http.get<PastoralDomain[]>(GET_URL_GET_CURRENT_USER_PASTORAL_DOMAIN);
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class DomainMemberShipService extends CombinedKeyCrudService<DomainMemberRelationship> {
|
|
||||||
|
|
||||||
constructor(protected http: HttpClient) {
|
|
||||||
super(http, RELATIONSHIP_BASE_URL);
|
|
||||||
}
|
|
||||||
assignCellGroups(data: DomainMemberRelationship[]) {
|
|
||||||
return this.http.post<boolean>(POST_URL_ASSIGN_CELL_GROUPS,
|
|
||||||
JSON.stringify(data), {
|
|
||||||
headers: {
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
return this.getCurrentUserPastoralDomain().pipe(map(result => {
|
||||||
|
this.domains = result;
|
||||||
|
this.initialized.next(true);
|
||||||
|
return result;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public get myCellGroup(): PastoralDomain {
|
||||||
|
return this.domains.find(d => d.type == DomainType.CellGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get myHappinessGroup(): PastoralDomain {
|
||||||
|
return this.domains.find(d => d.type == DomainType.HappinessGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
joinDomain(domainId: string) {
|
||||||
|
|
||||||
|
return this.domainMemberShipService.addMemberIntoGroup(domainId, this.session.loginUserId).pipe(
|
||||||
|
map(firstResult => { return firstResult }),
|
||||||
|
mergeMap(
|
||||||
|
firstResult => {
|
||||||
|
if (firstResult) {
|
||||||
|
return this.initialize();
|
||||||
|
} else {
|
||||||
|
return Observable.of(this.domains);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
src/app/services/file.service.spec.ts
Normal file
16
src/app/services/file.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { FileService } from './file.service';
|
||||||
|
|
||||||
|
describe('FileService', () => {
|
||||||
|
let service: FileService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(FileService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
15
src/app/services/file.service.ts
Normal file
15
src/app/services/file.service.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { environment } from '../../environments/environment';
|
||||||
|
const FilePath_URL = (id: string = null) => { return `${environment.apiUrl}/Files?filePath=${(id ? `/${id}` : '')}` }
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class FileService {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
|
||||||
|
ImageUrl(imagePath: string) {
|
||||||
|
return FilePath_URL(imagePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user