forked from Kispi/Core
feat(webapp): add banker login
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
0b087a38bf
commit
36638fbf74
10 changed files with 291 additions and 118 deletions
|
@ -1,111 +1,4 @@
|
|||
[
|
||||
{
|
||||
"id": "w85pgrtrmovf916",
|
||||
"name": "transactions",
|
||||
"type": "base",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"id": "5aeh5giq",
|
||||
"name": "account",
|
||||
"type": "relation",
|
||||
"system": false,
|
||||
"required": true,
|
||||
"options": {
|
||||
"collectionId": "74ftooxenpeq14b",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": [
|
||||
"firstName",
|
||||
"lastName"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "2bzqyeuk",
|
||||
"name": "label",
|
||||
"type": "text",
|
||||
"system": false,
|
||||
"required": true,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "zsx9i8w7",
|
||||
"name": "amount",
|
||||
"type": "number",
|
||||
"system": false,
|
||||
"required": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"listRule": "",
|
||||
"viewRule": "",
|
||||
"createRule": "",
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "5msnfxat1sc2c1r",
|
||||
"name": "companyTransactions",
|
||||
"type": "base",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"id": "7rnyupog",
|
||||
"name": "account",
|
||||
"type": "relation",
|
||||
"system": false,
|
||||
"required": true,
|
||||
"options": {
|
||||
"collectionId": "s854d2w72fvyl54",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ruby9fp9",
|
||||
"name": "label",
|
||||
"type": "text",
|
||||
"system": false,
|
||||
"required": true,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "4hiu46ib",
|
||||
"name": "amount",
|
||||
"type": "number",
|
||||
"system": false,
|
||||
"required": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"listRule": "",
|
||||
"viewRule": "",
|
||||
"createRule": "",
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "s854d2w72fvyl54",
|
||||
"name": "companies",
|
||||
|
@ -431,5 +324,135 @@
|
|||
"updateRule": "(@request.data.id = null && @request.data.accountNumber = null && @request.data.firstName = null && @request.data.lastName = null && @request.data.grade = null && @request.data.created = null && @request.data.updated = null && @request.data.company = null && @request.data.shift = null && @request.data.wage = null) || (@request.data.id = null && @request.data.accountNumber = null && @request.data.firstName = null && @request.data.lastName = null && @request.data.created = null && @request.data.updated = null && @request.data.company = null && @request.auth.id = company.id)",
|
||||
"deleteRule": null,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "w1au07idupp27qv",
|
||||
"name": "bankers",
|
||||
"type": "auth",
|
||||
"system": false,
|
||||
"schema": [],
|
||||
"indexes": [],
|
||||
"listRule": null,
|
||||
"viewRule": null,
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"options": {
|
||||
"allowEmailAuth": true,
|
||||
"allowOAuth2Auth": true,
|
||||
"allowUsernameAuth": true,
|
||||
"exceptEmailDomains": null,
|
||||
"manageRule": null,
|
||||
"minPasswordLength": 8,
|
||||
"onlyEmailDomains": null,
|
||||
"requireEmail": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "w85pgrtrmovf916",
|
||||
"name": "transactions",
|
||||
"type": "base",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"id": "5aeh5giq",
|
||||
"name": "account",
|
||||
"type": "relation",
|
||||
"system": false,
|
||||
"required": true,
|
||||
"options": {
|
||||
"collectionId": "74ftooxenpeq14b",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": [
|
||||
"firstName",
|
||||
"lastName"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "2bzqyeuk",
|
||||
"name": "label",
|
||||
"type": "text",
|
||||
"system": false,
|
||||
"required": true,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "zsx9i8w7",
|
||||
"name": "amount",
|
||||
"type": "number",
|
||||
"system": false,
|
||||
"required": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"listRule": "@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id",
|
||||
"viewRule": "@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id",
|
||||
"createRule": "@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id",
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "5msnfxat1sc2c1r",
|
||||
"name": "companyTransactions",
|
||||
"type": "base",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"id": "7rnyupog",
|
||||
"name": "account",
|
||||
"type": "relation",
|
||||
"system": false,
|
||||
"required": true,
|
||||
"options": {
|
||||
"collectionId": "s854d2w72fvyl54",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ruby9fp9",
|
||||
"name": "label",
|
||||
"type": "text",
|
||||
"system": false,
|
||||
"required": true,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "4hiu46ib",
|
||||
"name": "amount",
|
||||
"type": "number",
|
||||
"system": false,
|
||||
"required": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"listRule": "@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id",
|
||||
"viewRule": "@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id",
|
||||
"createRule": "@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id",
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"options": {}
|
||||
}
|
||||
]
|
|
@ -1,6 +1,7 @@
|
|||
<template>
|
||||
<div class="relative">
|
||||
<input
|
||||
ref="input"
|
||||
:value="value"
|
||||
type="number"
|
||||
class="input w-full border-primary text-right"
|
||||
|
@ -26,6 +27,10 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
const input = ref<InstanceType<typeof HTMLInputElement>>();
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
suffixMargin?: boolean,
|
||||
perHour?: boolean,
|
||||
|
@ -53,9 +58,19 @@ function onKeyDown(event: KeyboardEvent) {
|
|||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
if(input.value) {
|
||||
input.value.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: [value: number],
|
||||
}>();
|
||||
|
||||
defineExpose({
|
||||
reset,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -5,6 +5,9 @@
|
|||
:required="required"
|
||||
:placeholder="placeholder"
|
||||
class="input w-full border-primary"
|
||||
:class="{
|
||||
'!border-error': error,
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
@ -22,6 +25,10 @@ defineProps({
|
|||
type: String,
|
||||
default: '',
|
||||
},
|
||||
error: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
/* global defineModel */
|
||||
|
|
63
webapp/src/components/molecules/MoleculeBankerAuthDialog.vue
Normal file
63
webapp/src/components/molecules/MoleculeBankerAuthDialog.vue
Normal file
|
@ -0,0 +1,63 @@
|
|||
<template>
|
||||
<div class="hero min-h-full">
|
||||
<form
|
||||
class="hero-content mx-auto flex-col text-center"
|
||||
@submit.prevent="handleAuth"
|
||||
>
|
||||
<AtomInput
|
||||
v-model="username"
|
||||
placeholder="Nutzername"
|
||||
type="text"
|
||||
:error="error"
|
||||
required
|
||||
/>
|
||||
<AtomInput
|
||||
v-model="password"
|
||||
placeholder="Passwort"
|
||||
type="password"
|
||||
:error="error"
|
||||
required
|
||||
/>
|
||||
<div
|
||||
v-if="error"
|
||||
class="alert alert-error flex w-[211px] items-center gap-2"
|
||||
>
|
||||
<XCircleIcon class="h-12 w-12" />
|
||||
<span class="text-base font-normal">Nutzername oder Passwort falsch.</span>
|
||||
</div>
|
||||
<button class="btn-primary btn gap-2 self-end">
|
||||
<ArrowRightOnRectangleIcon class="h-6 w-6" />
|
||||
Login
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { ArrowRightOnRectangleIcon, XCircleIcon } from '@heroicons/vue/24/outline';
|
||||
import AtomInput from '../atoms/AtomInput.vue';
|
||||
|
||||
const username = ref('');
|
||||
const password = ref('');
|
||||
const error = ref(false);
|
||||
|
||||
async function handleAuth() {
|
||||
try {
|
||||
await AuthService.loginAsBanker(username.value, password.value);
|
||||
} catch (e) {
|
||||
error.value = true;
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
watch([username, password], () => {
|
||||
error.value = false;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
|
@ -8,8 +8,9 @@
|
|||
<div class="flex place-items-center justify-between">
|
||||
<span>{{ inputLabel }}</span>
|
||||
<AtomCurrencyInput
|
||||
v-model="amount"
|
||||
ref="input"
|
||||
class="w-4/12"
|
||||
@change="amount = $event"
|
||||
@keyup.esc="modal?.close()"
|
||||
/>
|
||||
</div>
|
||||
|
@ -40,6 +41,7 @@ import AtomCurrencyInput from '../atoms/AtomCurrencyInput.vue';
|
|||
import AtomModal from '../atoms/AtomModal.vue';
|
||||
|
||||
const modal = ref<InstanceType<typeof AtomModal>>();
|
||||
const input= ref<InstanceType<typeof AtomCurrencyInput>>();
|
||||
const amount = ref();
|
||||
|
||||
defineProps({
|
||||
|
@ -64,7 +66,9 @@ defineProps({
|
|||
const emit = defineEmits(['submit']);
|
||||
|
||||
function handleClose() {
|
||||
amount.value = '';
|
||||
if(input.value) {
|
||||
input.value.reset();
|
||||
}
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
|
|
|
@ -61,6 +61,21 @@
|
|||
</li>
|
||||
<li class="menu-title !p-0" />
|
||||
</template>
|
||||
<template v-if="isBanker">
|
||||
<li class="pointer-events-none rounded-md bg-info text-warning-content">
|
||||
<span>
|
||||
Angemeldet als Banker
|
||||
<BuildingLibraryIcon class="h-6 w-6" />
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span @click="AuthService.logout()">
|
||||
<ArrowRightOnRectangleIcon class="h-6 w-6" />
|
||||
Abmelden
|
||||
</span>
|
||||
</li>
|
||||
<li class="menu-title !p-0" />
|
||||
</template>
|
||||
<li
|
||||
v-for="navigationEntry of navigationEntries"
|
||||
:class="getNavigationEntryClass(navigationEntry)"
|
||||
|
@ -96,11 +111,12 @@ import { useRouter } from 'vue-router';
|
|||
import { INavigationEntry } from '../../interfaces/navigation-entry.interface';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { isDark, toggleDark } from '../../utils/darkMode';
|
||||
import { ArrowRightOnRectangleIcon, Bars3Icon, ExclamationTriangleIcon, MoonIcon, SunIcon } from '@heroicons/vue/24/outline';
|
||||
import { ArrowRightOnRectangleIcon, Bars3Icon, BuildingLibraryIcon, ExclamationTriangleIcon, MoonIcon, SunIcon } from '@heroicons/vue/24/outline';
|
||||
import AtomLogo from '../atoms/AtomLogo.vue';
|
||||
import AtomSwap from '../atoms/AtomSwap.vue';
|
||||
|
||||
const isAdmin = ref(false);
|
||||
const isBanker = ref(false);
|
||||
const hideNavigation = ref(false);
|
||||
const router = useRouter();
|
||||
const drawerCheckbox = ref();
|
||||
|
@ -125,10 +141,12 @@ function getNavigationEntryClass(navigationEntry: INavigationEntry) {
|
|||
}
|
||||
|
||||
useEventBus<boolean>('isAdmin').on(state => (isAdmin.value = state));
|
||||
useEventBus<boolean>('isBanker').on(state => (isBanker.value = state));
|
||||
useEventBus<boolean>('hideNavigation').on(state => (hideNavigation.value = state));
|
||||
|
||||
onMounted(() => {
|
||||
isAdmin.value = AuthService.isAdmin();
|
||||
isBanker.value = AuthService.isBanker();
|
||||
});
|
||||
|
||||
router.afterEach(() => {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<div>
|
||||
<MoleculeBankerAuthDialog
|
||||
v-if="!isBanker && !AuthService.isAdmin()"
|
||||
/>
|
||||
<div v-else>
|
||||
<div
|
||||
v-if="account || company"
|
||||
class="hero-content flex-col pt-0 text-center lg:p-6"
|
||||
|
@ -94,26 +97,29 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onUnmounted, ref } from 'vue';
|
||||
import { onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { onKeyStroke, promiseTimeout } from '@vueuse/core';
|
||||
import { onKeyStroke, promiseTimeout, useEventBus } from '@vueuse/core';
|
||||
import { RecordSubscription, UnsubscribeFunc } from 'pocketbase';
|
||||
import { AccountsResponse, CompaniesResponse, SettingsResponse, TransactionsResponse } from '../../types/pocketbase.types';
|
||||
import { AccountService } from '../../services/account.service';
|
||||
import { AccountType, BankService, TransactionType } from '../../services/bank.service';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { CompanyService } from '../../services/company.service';
|
||||
import { CurrencyService } from '../../services/currency.service';
|
||||
import { SettingsService } from '../../services/settings.service';
|
||||
import { ChevronDownIcon, ChevronUpIcon, XCircleIcon } from '@heroicons/vue/24/outline';
|
||||
import AtomHeroText from '../atoms/AtomHeroText.vue';
|
||||
import MoleculeInputModal from '../molecules/MoleculeInputModal.vue';
|
||||
import MoleculeTransactionTable from '../molecules/MoleculeTransactionTable.vue';
|
||||
import { SettingsService } from '../../services/settings.service';
|
||||
import AtomLogo from '../atoms/AtomLogo.vue';
|
||||
import MoleculeBankerAuthDialog from '../molecules/MoleculeBankerAuthDialog.vue';
|
||||
|
||||
const router = useRouter();
|
||||
const subscription = ref<UnsubscribeFunc>();
|
||||
const companySubscription = ref<UnsubscribeFunc>();
|
||||
|
||||
const isBanker = ref(false);
|
||||
const account = ref<AccountsResponse|null>();
|
||||
const company = ref<CompaniesResponse|null>();
|
||||
const transactions = ref<TransactionsResponse[]>();
|
||||
|
@ -132,6 +138,7 @@ if(router.currentRoute.value.query.accountNumber) {
|
|||
}
|
||||
|
||||
onKeyStroke(['e', 'a'], (e) => {
|
||||
if(!isBanker.value) { return; }
|
||||
e.preventDefault();
|
||||
if(depositModal.value?.isOpen() || withdrawModal.value?.isOpen()) {
|
||||
return;
|
||||
|
@ -147,6 +154,7 @@ onKeyStroke(['e', 'a'], (e) => {
|
|||
});
|
||||
|
||||
onKeyStroke(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'Enter'], (e) => {
|
||||
if(!isBanker.value) { return; }
|
||||
if(depositModal.value?.isOpen() || withdrawModal.value?.isOpen()) {
|
||||
return;
|
||||
}
|
||||
|
@ -243,15 +251,26 @@ function handleRealtimeUpdates(transactionSubscription: RecordSubscription<Trans
|
|||
}
|
||||
|
||||
onMounted(async () => {
|
||||
subscription.value = await BankService.subscribeToTransactionChanges(handleRealtimeUpdates);
|
||||
companySubscription.value = await BankService.subscribeToCompanyTransactionChanges(handleRealtimeUpdates);
|
||||
settings.value = await SettingsService.getSettings();
|
||||
isBanker.value = AuthService.isBanker();
|
||||
});
|
||||
|
||||
useEventBus<boolean>('isBanker').on(state => (isBanker.value = state));
|
||||
|
||||
onUnmounted(() => {
|
||||
subscription.value?.();
|
||||
companySubscription.value?.();
|
||||
});
|
||||
|
||||
watch(isBanker, async (newValue) => {
|
||||
if(newValue) {
|
||||
subscription.value = await BankService.subscribeToTransactionChanges(handleRealtimeUpdates);
|
||||
companySubscription.value = await BankService.subscribeToCompanyTransactionChanges(handleRealtimeUpdates);
|
||||
settings.value = await SettingsService.getSettings();
|
||||
} else {
|
||||
subscription.value?.();
|
||||
companySubscription.value?.();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Admin } from 'pocketbase';
|
||||
import { PocketbaseService } from './pocketbase.service';
|
||||
import { useEventBus } from '@vueuse/core';
|
||||
import { BankersResponse, Collections } from '../types/pocketbase.types';
|
||||
|
||||
const API = PocketbaseService.getApi();
|
||||
|
||||
|
@ -29,5 +30,22 @@ export class AuthService {
|
|||
public static logout(): void {
|
||||
API.authStore.clear();
|
||||
useEventBus<boolean>('isAdmin').emit(false);
|
||||
useEventBus<boolean>('isBanker').emit(false);
|
||||
}
|
||||
public static async loginAsBanker(username: string, password: string): Promise<BankersResponse> {
|
||||
const response = await API.collection(Collections.Bankers).authWithPassword<BankersResponse>(username, password);
|
||||
if(response) {
|
||||
useEventBus<boolean>('isBanker').emit(true);
|
||||
return response.record;
|
||||
}
|
||||
throw new Error('Invalid credentials');
|
||||
}
|
||||
public static isBanker(): boolean {
|
||||
if(API.authStore.model && API.authStore.model?.collectionName == Collections.Bankers) {
|
||||
useEventBus<boolean>('isBanker').emit(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -30,7 +30,7 @@ export class CompanyService {
|
|||
}
|
||||
public static isAuthenticated(): boolean {
|
||||
if(API.authStore.isValid && API.authStore.model) {
|
||||
return Boolean(API.authStore.model.collectionId);
|
||||
return API.authStore.model.collectionName == Collections.Companies;
|
||||
}
|
||||
this.logout();
|
||||
return false;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
export enum Collections {
|
||||
Accounts = "accounts",
|
||||
AccountsList = "accountsList",
|
||||
Bankers = "bankers",
|
||||
Companies = "companies",
|
||||
CompanyTransactions = "companyTransactions",
|
||||
Settings = "settings",
|
||||
|
@ -54,6 +55,8 @@ export type AccountsListRecord<Tbalance = unknown, Tname = unknown> = {
|
|||
balance?: null | Tbalance
|
||||
}
|
||||
|
||||
export type BankersRecord = never
|
||||
|
||||
export type CompaniesRecord = {
|
||||
accountNumber?: string
|
||||
name: string
|
||||
|
@ -84,6 +87,7 @@ export type TransactionsRecord = {
|
|||
// Response types include system fields and match responses from the PocketBase API
|
||||
export type AccountsResponse<Texpand = unknown> = Required<AccountsRecord> & BaseSystemFields<Texpand>
|
||||
export type AccountsListResponse<Tbalance = unknown, Tname = unknown, Texpand = unknown> = Required<AccountsListRecord<Tbalance, Tname>> & BaseSystemFields<Texpand>
|
||||
export type BankersResponse<Texpand = unknown> = Required<BankersRecord> & AuthSystemFields<Texpand>
|
||||
export type CompaniesResponse<Texpand = unknown> = Required<CompaniesRecord> & AuthSystemFields<Texpand>
|
||||
export type CompanyTransactionsResponse<Texpand = unknown> = Required<CompanyTransactionsRecord> & BaseSystemFields<Texpand>
|
||||
export type SettingsResponse<Texpand = unknown> = Required<SettingsRecord> & BaseSystemFields<Texpand>
|
||||
|
@ -94,6 +98,7 @@ export type TransactionsResponse<Texpand = unknown> = Required<TransactionsRecor
|
|||
export type CollectionRecords = {
|
||||
accounts: AccountsRecord
|
||||
accountsList: AccountsListRecord
|
||||
bankers: BankersRecord
|
||||
companies: CompaniesRecord
|
||||
companyTransactions: CompanyTransactionsRecord
|
||||
settings: SettingsRecord
|
||||
|
@ -103,6 +108,7 @@ export type CollectionRecords = {
|
|||
export type CollectionResponses = {
|
||||
accounts: AccountsResponse
|
||||
accountsList: AccountsListResponse
|
||||
bankers: BankersResponse
|
||||
companies: CompaniesResponse
|
||||
companyTransactions: CompanyTransactionsResponse
|
||||
settings: SettingsResponse
|
||||
|
|
Loading…
Reference in a new issue