Home Reference Source

src/groups/GroupRepository.ts

import {Immutable} from 'immer';
import {Observable, concat, defer, map, scan, tap} from 'rxjs';

import Logs from '../Logs';
import {GroupService} from '../wac-proxy/wac-stack/groups/GroupService';
import {GroupDto} from '../wac-proxy/wac-stack/groups/types';

import {Group} from './Group';

const log = Logs.instance.getLogger('SippoJS/GroupRepository');

function fromGroupDto(data: GroupDto): Group {
	return Group.of({
		id: data.groupId,
		name: data.name,
		owner: data.owner.id,
		participants: data.participants,
	});
}

type Action = Immutable<{
	type: 'DELETE';
	body: {groupId: string};
} | {
	type: 'INIT';
	body: GroupDto[];
} | {
	type: 'UPDATE';
	body: GroupDto;
}>;

const reducer = (state: Group[], action: Action): Group[] => {
	switch (action.type) {
		case 'INIT':
			return action.body.map(datum => fromGroupDto(datum));
		case 'DELETE':
			return state.filter(group => group.id !== action.body.groupId);
		case 'UPDATE':
			if (state.findIndex(group => group.id === action.body.groupId) >= 0) {
				return state.map(group => group.id === action.body.groupId ? fromGroupDto(action.body) : group);
			}
			return [...state, fromGroupDto(action.body)];
	}
};

/**
 * This class allows manager the groups. To obtain an instance of the
 * class @link {Session#getGroupRepository} method must be used.
 */
export class GroupRepository {
	groups$: Observable<Group[]>;

	constructor(
		private groupService: GroupService,
	) {
		this.groups$ = defer(() => this.getActions()).pipe(
			tap(x => log.debug('action', x)),
			scan(reducer, []),
			tap(x => log.debug('state', x)),
		);
	}

	private getActions(): Observable<Action> {
		return concat(
			this.groupService.fetch().pipe(map((groupDtos): Action =>
				({type: 'INIT', body: groupDtos}),
			)),
			this.groupService.event$.pipe(map((eventDto): Action => {
				switch (eventDto.method) {
					case 'PUT':
					case 'POST':
						return {type: 'UPDATE', body: eventDto.body};
					case 'DELETE':
						return {type: 'DELETE', body: eventDto.body};
				}
			})),
		);
	}

	/**
	 * Creates a new group
	 */
	async createGroup(name: string, participants: string[]): Promise<void> {
		await this.groupService.create(name, participants);
	}

	/**
	 * Saves a group
	 */
	async saveGroup(group: Group): Promise<void> {
		await this.groupService.update(group.id, group.name, group.participants);
	}

	/**
	 * Deletes a group
	 */
	async deleteGroup(group: Group): Promise<void> {
		await this.groupService.delete(group.id);
	}
}