chrone: sperate client and server to different repos.

This commit is contained in:
a.bouhuolia
2021-09-21 17:13:53 +02:00
parent e011b2a82b
commit 18df5530c7
10015 changed files with 17686 additions and 97524 deletions

35
src/hooks/async.js Normal file
View File

@@ -0,0 +1,35 @@
import {useState, useCallback, useEffect} from 'react';
const useAsync = (asyncFunction, immediate = true) => {
const [pending, setPending] = useState(false);
const [value, setValue] = useState(null);
const [error, setError] = useState(null);
// The execute function wraps asyncFunction and
// handles setting state for pending, value, and error.
// useCallback ensures the below useEffect is not called
// on every render, but only if asyncFunction changes.
const execute = useCallback((...args) => {
setPending(true);
setValue(null);
setError(null);
return asyncFunction(...args)
.then(response => setValue(response))
.catch(error => setError(error))
.finally(() => setPending(false));
}, [asyncFunction]);
// Call execute if we want to fire it right away.
// Otherwise execute can be called later, such as
// in an onClick handler.
useEffect(() => {
if (immediate) {
execute();
}
}, []);
return { execute, pending, value, error };
};
export default useAsync;

108
src/hooks/index.js Normal file
View File

@@ -0,0 +1,108 @@
import React, { useRef, useEffect, useMemo } from 'react';
import useAsync from './async';
import useAutofocus from './useAutofocus';
// import use from 'async';
/**
* A custom useEffect hook that only triggers on updates, not on initial mount
* Idea stolen from: https://stackoverflow.com/a/55075818/1526448
* @param {Function} effect
* @param {Array<any>} dependencies
*/
export function useUpdateEffect(effect, dependencies = []) {
const isInitialMount = useRef(true);
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
effect();
}
}, dependencies);
}
export function useIsValuePassed(value, compatatorValue) {
const cache = useRef([value]);
useEffect(() => {
if (cache.current.indexOf(value) === -1) {
cache.current.push(value);
}
}, [value]);
return cache.current.indexOf(compatatorValue) !== -1;
}
const isCurrentFocus = (autoFocus, columnId, rowIndex) => {
let _columnId;
let _rowIndex;
if (Array.isArray(autoFocus)) {
_columnId = autoFocus[0];
_rowIndex = autoFocus[1] || 0;
}
_rowIndex = parseInt(_rowIndex, 10);
return columnId === _columnId && _rowIndex === rowIndex;
};
export function useCellAutoFocus(ref, autoFocus, columnId, rowIndex) {
const focus = useMemo(
() => isCurrentFocus(autoFocus, columnId, rowIndex),
[autoFocus, columnId, rowIndex],
);
useEffect(() => {
if (ref.current && focus) {
ref.current.focus();
}
}, [ref, focus]);
return ref;
}
export * from './useRequestPdf';
export { useAsync, useAutofocus };
// Hook
export function useLocalStorage(key, initialValue) {
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = React.useState(() => {
try {
// Get from local storage by key
const item = window.localStorage.getItem(key);
// Parse stored json or if none return initialValue
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = (value) => {
try {
// Allow value to be a function so we have same API as useState
const valueToStore =
value instanceof Function ? value(storedValue) : value;
// Save state
setStoredValue(valueToStore);
// Save to local storage
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
// A more advanced implementation would handle the error case
console.log(error);
}
};
return [storedValue, setValue];
}
export function useMemorizedColumnsWidths(tableName) {
const [get, save] = useLocalStorage(`${tableName}.columns_widths`, {});
const handleColumnResizing = (current, columnWidth, columnsResizing) => {
save(columnsResizing.columnWidths);
};
return [get, save, handleColumnResizing];
}

View File

@@ -0,0 +1,131 @@
import { useRequestQuery } from '../../useQueryRequest';
import { RESOURCES_TYPES } from 'common/resourcesTypes';
/**
*
* @param {string} type
* @param {string} searchKeyword
* @param {*} query
* @returns
*/
export function useResourceData(type, query, props) {
const url = getResourceUrlFromType(type);
return useRequestQuery(
['UNIVERSAL_SEARCH', type, query],
{ method: 'get', url, params: query },
{
select: transformResourceData(type),
defaultData: {
items: [],
},
...props,
},
);
}
/**
* Retrieve the resource url by the given resource type.
* @param {string} type
* @returns {string}
*/
function getResourceUrlFromType(type) {
const config = {
[RESOURCES_TYPES.INVOICE]: '/sales/invoices',
[RESOURCES_TYPES.ESTIMATE]: '/sales/estimates',
[RESOURCES_TYPES.ITEM]: '/items',
[RESOURCES_TYPES.RECEIPT]: '/sales/receipts',
[RESOURCES_TYPES.BILL]: '/purchases/bills',
[RESOURCES_TYPES.PAYMENT_RECEIVE]: '/sales/payment_receives',
[RESOURCES_TYPES.PAYMENT_MADE]: '/purchases/bill_payments',
[RESOURCES_TYPES.CUSTOMER]: '/customers',
[RESOURCES_TYPES.VENDOR]: '/vendors',
[RESOURCES_TYPES.MANUAL_JOURNAL]: '/manual-journals',
[RESOURCES_TYPES.ACCOUNT]: '/accounts',
};
return config[type] || '';
}
/**
* Transformes invoices to resource data.
*/
const transformInvoices = (response) => ({
items: response.data.sales_invoices,
});
/**
* Transformes items to resource data.
*/
const transformItems = (response) => ({
items: response.data.items,
});
/**
* Transformes payment receives to resource data.
*/
const transformPaymentReceives = (response) => ({
items: response.data.payment_receives,
});
/**
* Transformes customers to resoruce data.
*/
const transformCustomers = (response) => ({
items: response.data.customers,
});
/**
* Transformes customers to resoruce data.
*/
const transformVendors = (response) => ({
items: response.data.vendors,
});
const transformPaymentMades = (response) => ({
items: response.data.bill_payments,
});
const transformSaleReceipts = (response) => ({
items: response.data.data,
});
const transformBills = (response) => ({
items: response.data.bills,
});
const transformManualJournals = (response) => ({
items: response.data.manual_journals,
});
const transformsEstimates = (response) => ({
items: response.data.sales_estimates,
});
const transformAccounts = (response) => ({
items: response.data.accounts,
})
/**
* Detarmines the transformer based on the given resource type.
* @param {string} type - Resource type.
*/
const transformResourceData = (type) => (response) => {
const pairs = {
[RESOURCES_TYPES.ESTIMATE]: transformsEstimates,
[RESOURCES_TYPES.INVOICE]: transformInvoices,
[RESOURCES_TYPES.RECEIPT]: transformSaleReceipts,
[RESOURCES_TYPES.ITEM]: transformItems,
[RESOURCES_TYPES.PAYMENT_RECEIVE]: transformPaymentReceives,
[RESOURCES_TYPES.PAYMENT_MADE]: transformPaymentMades,
[RESOURCES_TYPES.CUSTOMER]: transformCustomers,
[RESOURCES_TYPES.VENDOR]: transformVendors,
[RESOURCES_TYPES.BILL]: transformBills,
[RESOURCES_TYPES.MANUAL_JOURNAL]: transformManualJournals,
[RESOURCES_TYPES.ACCOUNT]: transformAccounts
};
return {
...pairs[type](response),
_type: type,
};
};

View File

@@ -0,0 +1,41 @@
import { getUniversalSearchBind } from '../../../containers/UniversalSearch/utils';
import { useResourceData } from '../GenericResource';
/**
* Transformes the resource data to search entries based on
* the given resource type.
* @param {string} type
* @param {any} resource
* @returns
*/
function transfromResourceDataToSearch(resource) {
const selectItem = getUniversalSearchBind(resource._type, 'itemSelect');
return resource.items
.map((item) => ({
...selectItem ? selectItem(item) : {},
_type: resource._type,
}));
}
/**
*
* @param {*} type
* @param {*} searchKeyword
* @returns
*/
export function useUniversalSearch(type, searchKeyword, props) {
const { data, ...restProps } = useResourceData(
type,
{
search_keyword: searchKeyword,
},
props,
);
const searchData = transfromResourceDataToSearch(data);
return {
data: searchData,
...restProps,
};
}

172
src/hooks/query/accounts.js Normal file
View File

@@ -0,0 +1,172 @@
import { useMutation, useQueryClient } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest';
import t from './types';
// Transform the account.
const transformAccount = (response) => {
return response.data.account;
};
const commonInvalidateQueries = (query) => {
// Invalidate accounts.
query.invalidateQueries(t.ACCOUNTS);
query.invalidateQueries(t.ACCOUNT);
// Invalidate financial reports.
query.invalidateQueries(t.FINANCIAL_REPORT);
};
/**
* Retrieve accounts list.
*/
export function useAccounts(query, props) {
return useRequestQuery(
[t.ACCOUNTS, query],
{ method: 'get', url: 'accounts', params: query },
{
select: (res) => res.data.accounts,
defaultData: [],
...props,
},
);
}
/**
* Retrieve the given account details.
* @param {number} id - Account id.
*/
export function useAccount(id, props) {
return useRequestQuery(
[t.ACCOUNT, id],
{ method: 'get', url: `accounts/${id}` },
{
select: transformAccount,
defaultData: {},
...props,
},
);
}
/**
* Retrieve accounts types list.
*/
export function useAccountsTypes(props) {
return useRequestQuery(
[t.ACCOUNTS_TYPES],
{ method: 'get', url: 'account_types' },
{
select: (res) => res.data.account_types,
defaultData: [],
...props,
},
);
}
/**
* Creates account.
*/
export function useCreateAccount(props) {
const client = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('accounts', values), {
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(client);
},
...props,
});
}
/**
* Edits the given account.
*/
export function useEditAccount(props) {
const client = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`accounts/${id}`, values),
{
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(client);
},
...props,
},
);
}
/**
* Edits the given account.
*/
export function useDeleteAccount(props) {
const client = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`accounts/${id}`), {
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(client);
},
...props,
});
}
/**
* Actiavte the give account.
*/
export function useActivateAccount(props) {
const client = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`accounts/${id}/activate`), {
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(client);
},
...props,
});
}
/**
* Inactivate the given account.
*/
export function useInactivateAccount(props) {
const query = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`accounts/${id}/inactivate`), {
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(query);
},
...props,
});
}
/**
* Retrieve account transactions.
*/
export function useAccountTransactions(id, props) {
return useRequestQuery(
[t.ACCOUNT_TRANSACTION, id],
{ method: 'get', url: `accounts/transactions?account_id=${id}` },
{
select: (res) => res.data.transactions,
defaultData: [],
...props,
},
);
}
export function useRefreshAccounts() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries(t.ACCOUNTS);
},
};
}

View File

@@ -0,0 +1,71 @@
import { useMutation } from 'react-query';
import useApiRequest from '../useRequest';
import { setCookie } from '../../utils';
/**
* Saves the response data to cookies.
*/
function setAuthLoginCookies(data) {
setCookie('token', data.token);
setCookie('authenticated_user_id', data.user.id);
setCookie('organization_id', data.tenant.organization_id);
setCookie('tenant_id', data.tenant.id);
if (data?.tenant?.metadata?.language)
setCookie('locale', data.tenant.metadata.language);
}
/**
* Authentication login.
*/
export const useAuthLogin = (props) => {
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('auth/login', values), {
select: (res) => res.data,
onSuccess: (data) => {
// Set authentication cookies.
setAuthLoginCookies(data.data);
// Reboot the application.
window.location.reload();
},
...props,
});
};
/**
* Authentication register.
*/
export const useAuthRegister = (props) => {
const apiRequest = useApiRequest();
return useMutation(
(values) => apiRequest.post('auth/register', values),
props,
);
};
/**
* Authentication send reset password.
*/
export const useAuthSendResetPassword = (props) => {
const apiRequest = useApiRequest();
return useMutation(
(email) => apiRequest.post('auth/send_reset_password', email),
props,
);
};
/**
* Authentication reset password.
*/
export const useAuthResetPassword = (props) => {
const apiRequest = useApiRequest();
return useMutation(
([token, values]) => apiRequest.post(`auth/reset/${token}`, values),
props,
);
};

9
src/hooks/query/base.js Normal file
View File

@@ -0,0 +1,9 @@
// Query client config.
export const queryConfig = {
defaultOptions: {
queries: {
refetchOnWindowFocus: true,
staleTime: 30000,
},
},
};

180
src/hooks/query/bills.js Normal file
View File

@@ -0,0 +1,180 @@
import { useQueryClient, useMutation } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from 'utils';
import useApiRequest from '../useRequest';
import t from './types';
const commonInvalidateQueries = (queryClient) => {
// Invalidate bills.
queryClient.invalidateQueries(t.BILLS);
// Invalidate items.
queryClient.invalidateQueries(t.ITEMS);
queryClient.invalidateQueries(t.ITEM);
// Invalidate vendors.
queryClient.invalidateQueries([t.VENDORS]);
queryClient.invalidateQueries(t.VENDOR);
// Invalidate accounts.
queryClient.invalidateQueries(t.ACCOUNTS);
queryClient.invalidateQueries(t.ACCOUNT);
// Invalidate financial reports.
queryClient.invalidateQueries(t.FINANCIAL_REPORT);
};
/**
* Creates a new sale invoice.
*/
export function useCreateBill(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('purchases/bills', values), {
onSuccess: (res, values) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Edits the given sale invoice.
*/
export function useEditBill(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`purchases/bills/${id}`, values),
{
onSuccess: (res, [id, values]) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
// Invalidate bill query.
queryClient.invalidateQueries([t.BILL, id]);
},
...props,
},
);
}
/**
* Marks the given bill as open.
*/
export function useOpenBill(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`purchases/bills/${id}/open`), {
onSuccess: (res, id) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
// Invalidate bill query.
queryClient.invalidateQueries([t.BILL, id]);
},
...props,
});
}
/**
* Deletes the given sale invoice.
*/
export function useDeleteBill(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`purchases/bills/${id}`), {
onSuccess: (res, id) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
// Invalidate bill query.
queryClient.invalidateQueries([t.BILL, id]);
},
...props,
});
}
const transformBillsResponse = (response) => ({
bills: response.data.bills,
pagination: transformPagination(response.data.pagination),
filterMeta: response.data.filter_meta,
});
/**
* Retrieve sale invoices list with pagination meta.
*/
export function useBills(query, props) {
return useRequestQuery(
[t.BILLS, query],
{
method: 'get',
url: 'purchases/bills',
params: query,
},
{
select: transformBillsResponse,
defaultData: {
bills: [],
pagination: {
page: 1,
page_size: 12,
total: 0,
},
filterMeta: {},
},
...props,
},
);
}
/**
* Retrieve bill details of the given bill id.
* @param {number} id - Bill id.
*/
export function useBill(id, props) {
return useRequestQuery(
[t.BILL, id],
{ method: 'get', url: `/purchases/bills/${id}` },
{
select: (res) => res.data.bill,
defaultData: {},
...props,
},
);
}
/**
* Retrieve the due bills of the given vendor id.
* @param {number} vendorId -
*/
export function useDueBills(vendorId, props) {
return useRequestQuery(
[t.BILLS, t.BILLS_DUE, vendorId],
{
method: 'get',
url: 'purchases/bills/due',
params: { vendor_id: vendorId },
},
{
select: (res) => res.data.bills,
defaultData: [],
...props,
},
);
}
export function useRefreshBills() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries(t.BILLS);
},
};
}

View File

@@ -0,0 +1,83 @@
import { useMutation, useQueryClient } from 'react-query';
import useApiRequest from '../useRequest';
import { useQueryTenant } from '../useQueryRequest';
import t from './types';
// Common invalidate queries.
const commonInvalidateQueries = (queryClient) => {
// Invalidate vendors.
queryClient.invalidateQueries(t.VENDORS);
// Invalidate customers.
queryClient.invalidateQueries(t.CUSTOMERS);
};
/**
* Retrieve the contact duplicate.
*/
export function useContact(id, props) {
const apiRequest = useApiRequest();
return useQueryTenant(
['CONTACT', id],
() => apiRequest.get(`contacts/${id}`),
{
select: (res) => res.data.customer,
...props,
},
);
}
/**
* Retrieve the auto-complete contacts.
*/
export function useAutoCompleteContacts(props) {
const apiRequest = useApiRequest();
return useQueryTenant(
['CONTACTS', 'AUTO-COMPLETE'],
() => apiRequest.get('contacts/auto-complete'),
{
select: (res) => res.data.contacts,
defaultData: [],
...props,
},
);
}
/**
* Activate the given Contact.
*/
export function useActivateContact(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`contacts/${id}/activate`), {
onSuccess: (res, id) => {
// Invalidate specific contact.
queryClient.invalidateQueries([t.CONTACT, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Inactivate the given contact.
*/
export function useInactivateContact(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`contacts/${id}/inactivate`), {
onSuccess: (res, id) => {
// Invalidate specific item.
queryClient.invalidateQueries([t.CONTACT, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}

View File

@@ -0,0 +1,74 @@
import { useMutation, useQueryClient } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest';
import t from './types';
/**
* Create a new currency.
*/
export function useCreateCurrency(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('currencies', values), {
onSuccess: () => {
// Invalidate currencies.
queryClient.invalidateQueries(t.CURRENCIES);
},
...props,
});
}
/**
* Edits the given currency code.
*/
export function useEditCurrency(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([currencyCode, values]) =>
apiRequest.post(`currencies/${currencyCode}`, values),
{
onSuccess: () => {
// Invalidate currencies.
queryClient.invalidateQueries(t.CURRENCIES);
},
...props,
},
);
}
/**
* Deletes the given currency.
*/
export function useDeleteCurrency(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
(currencyCode) => apiRequest.delete(`currencies/${currencyCode}`),
{
onSuccess: () => {
// Invalidate currencies.
queryClient.invalidateQueries(t.CURRENCIES);
},
...props,
},
);
}
/**
* Retrieve the currencies list.
*/
export function useCurrencies(props) {
return useRequestQuery(
[t.CURRENCIES],
{ method: 'get', url: 'currencies' },
{
select: (res) => res.data.currencies,
defaultData: [],
...props
},
);
}

View File

@@ -0,0 +1,132 @@
import { useMutation, useQueryClient } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from 'utils';
import useApiRequest from '../useRequest';
import t from './types';
const defaultPagination = {
pageSize: 12,
page: 0,
pagesCount: 0,
};
const commonInvalidateQueries = (queryClient) => {
// Invalidate customers.
queryClient.invalidateQueries(t.CUSTOMERS);
// Invalidate the financial reports.
queryClient.invalidateQueries(t.ACCOUNTS);
queryClient.invalidateQueries(t.ACCOUNT);
// Invalidate the financial reports.
queryClient.invalidateQueries(t.FINANCIAL_REPORT);
};
// Customers response selector.
const customersSelector = (response) => ({
customers: response.data.customers,
pagination: transformPagination(response.data.pagination),
filterMeta: response.data.filter_meta,
});
/**
* Retrieve customers list with pagination meta.
*/
export function useCustomers(query, props) {
return useRequestQuery(
[t.CUSTOMERS, query],
{ method: 'get', url: `customers`, params: query },
{
select: customersSelector,
defaultData: {
customers: [],
pagination: defaultPagination,
filterMeta: {},
},
...props,
},
);
}
/**
* Edits the given customer details.
* @param {*} props
*/
export function useEditCustomer(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`customers/${id}`, values),
{
onSuccess: (res, [id, values]) => {
// Invalidate specific customer.
queryClient.invalidateQueries([t.CUSTOMER, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
},
);
}
/**
* Deletes the given customer.
*/
export function useDeleteCustomer(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`customers/${id}`), {
onSuccess: (res, id) => {
// Invalidate specific customer.
queryClient.invalidateQueries([t.CUSTOMER, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Creates a new customer.
*/
export function useCreateCustomer(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('customers', values), {
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Retrieve the customer details.
*/
export function useCustomer(id, props) {
return useRequestQuery(
[t.CUSTOMER, id],
{ method: 'get', url: `customers/${id}` },
{
select: (res) => res.data.customer,
defaultData: {},
...props,
},
);
}
export function useRefreshCustomers() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries(t.CUSTOMERS);
},
};
}

View File

@@ -0,0 +1,191 @@
import { useQueryClient, useMutation } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest';
import { useRequestPdf } from '../useRequestPdf';
import { transformPagination } from 'utils';
import t from './types';
const commonInvalidateQueries = (queryClient) => {
// Invalidate estimates.
queryClient.invalidateQueries(t.SALE_ESTIMATES);
};
/**
* Creates a new sale estimate.
*/
export function useCreateEstimate(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('sales/estimates', values), {
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
// Invalidate the settings.
queryClient.invalidateQueries([t.SETTING, t.SETTING_ESTIMATES]);
},
...props,
});
}
/**
* Edits the given sale estimate.
*/
export function useEditEstimate(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`sales/estimates/${id}`, values),
{
onSuccess: (res, [id, values]) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
// Invalidate specific sale estimate.
queryClient.invalidateQueries([t.SALE_ESTIMATE, id]);
},
...props,
},
);
}
/**
* Retrieve sale estimate details.
*/
export function useEstimate(id, props) {
return useRequestQuery(
[t.SALE_ESTIMATE, id],
{ method: 'get', url: `sales/estimates/${id}` },
{
select: (res) => res.data.estimate,
defaultData: {},
...props,
},
);
}
const transformEstimates = (res) => ({
estimates: res.data.sales_estimates,
pagination: transformPagination(res.data.pagination),
filterMeta: res.data.filter_meta,
});
/**
* Retrieve sale invoices list with pagination meta.
*/
export function useEstimates(query, props) {
return useRequestQuery(
[t.SALE_ESTIMATES, query],
{ method: 'get', url: 'sales/estimates', params: query },
{
select: transformEstimates,
defaultData: {
estimates: [],
pagination: {
page: 1,
pageSize: 12,
total: 0,
},
filterMeta: {},
},
...props,
},
);
}
/**
* Deletes the given sale invoice.
*/
export function useDeleteEstimate(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`sales/estimates/${id}`), {
onSuccess: (res, id) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
// Invalidate specific sale estimate.
queryClient.invalidateQueries([t.SALE_ESTIMATE, id]);
},
...props,
});
}
/**
* Mark the given estimate as delivered.
*/
export function useDeliverEstimate(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`sales/estimates/${id}/deliver`), {
onSuccess: (res, id) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
// Invalidate specific sale estimate.
queryClient.invalidateQueries([t.SALE_ESTIMATE, id]);
},
...props,
});
}
/**
* Mark the given estimate as approved.
*/
export function useApproveEstimate(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`sales/estimates/${id}/approve`), {
onSuccess: (res, id) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
// Invalidate specific sale estimate.
queryClient.invalidateQueries([t.SALE_ESTIMATE, id]);
},
...props,
});
}
/**
* Mark the given estimate as rejected.
*/
export function useRejectEstimate(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`sales/estimates/${id}/reject`), {
onSuccess: (res, id) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
// Invalidate specific sale estimate.
queryClient.invalidateQueries([t.SALE_ESTIMATE, id]);
},
...props,
});
}
/**
* Retrieve the estimate pdf document data,
*/
export function usePdfEstimate(estimateId) {
return useRequestPdf(`sales/estimates/${estimateId}`);
}
export function useRefreshEstimates() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries(t.SALE_ESTIMATES);
},
};
}

View File

@@ -0,0 +1,101 @@
import { useMutation, useQueryClient } from 'react-query';
import { defaultTo } from 'lodash';
import { useQueryTenant } from '../useQueryRequest';
import { transformPagination } from 'utils';
import useApiRequest from '../useRequest';
const defaultPagination = {
pageSize: 12,
page: 0,
pagesCount: 0,
};
/**
* Creates a new exchange rate.
*/
export function useCreateExchangeRate(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('exchange_rates', values), {
onSuccess: () => {
queryClient.invalidateQueries('EXCHANGES_RATES');
},
...props,
});
}
/**
* Edits the exchange rate.
*/
export function useEdiExchangeRate(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`exchange_rates/${id}`, values),
{
onSuccess: () => {
queryClient.invalidateQueries('EXCHANGES_RATES');
},
...props,
},
);
}
/**
* Deletes the exchange rate.
*/
export function useDeleteExchangeRate(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`exchange_rates/${id}`), {
onSuccess: () => {
queryClient.invalidateQueries('EXCHANGES_RATES');
},
...props,
});
}
/**
* Retrieve the exchange rate list.
*/
export function useExchangeRates(query, props) {
const apiRequest = useApiRequest();
const states = useQueryTenant(
['EXCHANGES_RATES', query],
() => apiRequest.get('exchange_rates', { params: query }),
{
select: (res) => ({
exchangesRates: res.data.exchange_rates.results,
pagination: transformPagination(res.data.exchange_rates.pagination),
filterMeta: res.data.filter_meta,
}),
...props,
},
);
return {
...states,
data: defaultTo(states.data, {
exchangesRates: [],
pagination: {
page: 1,
pageSize: 12,
total: 0,
},
filterMeta: {},
}),
};
}
export function useRefreshExchangeRate() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries('EXCHANGES_RATES');
},
};
}

158
src/hooks/query/expenses.js Normal file
View File

@@ -0,0 +1,158 @@
import { useMutation, useQueryClient } from 'react-query';
import useApiRequest from '../useRequest';
import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from 'utils';
import t from './types';
const defaultPagination = {
pageSize: 12,
page: 0,
pagesCount: 0,
};
// Common invalidate queries.
const commonInvalidateQueries = (queryClient) => {
// Invalidate expenses.
queryClient.invalidateQueries(t.EXPENSES);
// Invalidate accounts.
queryClient.invalidateQueries(t.ACCOUNTS);
queryClient.invalidateQueries(t.ACCOUNT);
// Invalidate financial reports.
queryClient.invalidateQueries(t.FINANCIAL_REPORT);
};
const transformExpenses = (response) => ({
expenses: response.data.expenses,
pagination: transformPagination(response.data.pagination),
filterMeta: response.data.filter_meta,
});
/**
* Retrieve the expenses list.
*/
export function useExpenses(query, props) {
return useRequestQuery(
[t.EXPENSES, query],
{
method: 'get',
url: `expenses`,
params: { ...query },
},
{
select: transformExpenses,
defaultData: {
expenses: [],
pagination: defaultPagination,
filterMeta: {},
},
...props,
},
);
}
/**
* Retrieve the expense details.
* @param {number} id - Expense id.
*/
export function useExpense(id, props) {
return useRequestQuery(
[t.EXPENSE, id],
{
method: 'get',
url: `expenses/${id}`,
},
{
select: (res) => res.data.expense,
defaultData: {},
...props,
},
);
}
/**
* Deletes the given expense.
*/
export function useDeleteExpense(props) {
const apiRequest = useApiRequest();
const queryClient = useQueryClient();
return useMutation((id) => apiRequest.delete(`expenses/${id}`), {
onSuccess: (res, id) => {
// Invalidate specific expense.
queryClient.invalidateQueries([t.EXPENSE, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Edits the given expense.
*/
export function useEditExpense(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`expenses/${id}`, values),
{
onSuccess: (res, [id, values]) => {
// Invalidate specific expense.
queryClient.invalidateQueries([t.EXPENSE, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
},
);
}
/**
* Creates the new expense.
*/
export function useCreateExpense(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('expenses', values), {
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Publishes the given expense.
*/
export function usePublishExpense(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`expenses/${id}/publish`), {
onSuccess: (res, id) => {
// Invalidate specific expense.
queryClient.invalidateQueries([t.EXPENSE, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
export function useRefreshExpenses() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries(t.EXPENSES);
},
};
}

View File

@@ -0,0 +1,489 @@
import { useRequestQuery } from '../useQueryRequest';
import {
trialBalanceSheetReducer,
balanceSheetRowsReducer,
profitLossSheetReducer,
generalLedgerTableRowsReducer,
journalTableRowsReducer,
ARAgingSummaryTableRowsMapper,
APAgingSummaryTableRowsMapper,
inventoryValuationReducer,
purchasesByItemsReducer,
salesByItemsReducer,
} from 'containers/FinancialStatements/reducers';
import t from './types';
/**
* Retrieve balance sheet.
*/
export function useBalanceSheet(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.BALANCE_SHEET, query],
{
method: 'get',
url: '/financial_statements/balance_sheet',
params: query,
},
{
select: (res) => ({
tableRows: balanceSheetRowsReducer(res.data.data),
...res.data,
}),
defaultData: {
data: [],
columns: [],
query: {},
tableRows: [],
},
...props,
},
);
}
/**
* Retrieve trial balance sheet.
*/
export function useTrialBalanceSheet(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.TRIAL_BALANCE_SHEET, query],
{
method: 'get',
url: '/financial_statements/trial_balance_sheet',
params: query,
},
{
select: (res) => ({
tableRows: trialBalanceSheetReducer(res.data.data),
...res.data,
}),
defaultData: {
tableRows: [],
data: [],
query: {},
},
...props,
},
);
}
/**
* Retrieve profit/loss (P&L) sheet.
*/
export function useProfitLossSheet(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.PROFIT_LOSS_SHEET, query],
{
method: 'get',
url: '/financial_statements/profit_loss_sheet',
params: query,
},
{
select: (res) => ({
tableRows: profitLossSheetReducer(res.data.data),
...res.data,
}),
defaultData: {
data: {},
tableRows: [],
columns: [],
query: {},
},
...props,
},
);
}
/**
* Retrieve general ledger (GL) sheet.
*/
export function useGeneralLedgerSheet(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.GENERAL_LEDGER, query],
{
method: 'get',
url: '/financial_statements/general_ledger',
params: query,
},
{
select: (res) => ({
tableRows: generalLedgerTableRowsReducer(res.data.data),
...res.data,
}),
defaultData: {
tableRows: [],
data: {},
query: {},
},
...props,
},
);
}
/**
* Retrieve journal sheet.
*/
export function useJournalSheet(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.JOURNAL, query],
{ method: 'get', url: '/financial_statements/journal', params: query },
{
select: (res) => ({
tableRows: journalTableRowsReducer(res.data.data),
...res.data,
}),
defaultData: {
data: {},
tableRows: [],
query: {},
},
...props,
},
);
}
/**
* Retrieve A/R aging summary report.
*/
export function useARAgingSummaryReport(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.AR_AGING_SUMMARY, query],
{
method: 'get',
url: '/financial_statements/receivable_aging_summary',
params: query,
},
{
select: (res) => ({
columns: res.data.columns,
data: res.data.data,
query: res.data.query,
tableRows: ARAgingSummaryTableRowsMapper({
customers: res.data.data.customers,
total: res.data.data.total,
columns: res.data.columns,
}),
}),
defaultData: {
data: {
customers: [],
total: {},
},
columns: [],
tableRows: [],
},
...props,
},
);
}
/**
* Retrieve A/P aging summary report.
*/
export function useAPAgingSummaryReport(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.AP_AGING_SUMMARY, query],
{
method: 'get',
url: '/financial_statements/payable_aging_summary',
params: query,
},
{
select: (res) => ({
columns: res.data.columns,
data: res.data.data,
query: res.data.query,
tableRows: APAgingSummaryTableRowsMapper({
vendors: res.data.data.vendors,
total: res.data.data.total,
columns: res.data.columns,
}),
}),
defaultData: {
data: {
vendors: [],
total: {},
},
columns: [],
tableRows: [],
},
...props,
},
);
}
/**
* Retrieve inventory valuation.
*/
export function useInventoryValuation(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.INVENTORY_VALUATION, query],
{
method: 'get',
url: '/financial_statements/inventory-valuation',
params: query,
},
{
select: (res) => ({
tableRows: inventoryValuationReducer(res.data.data),
...res.data,
}),
defaultData: {
tableRows: [],
data: [],
query: {},
},
...props,
},
);
}
/**
* Retrieve purchases by items.
*/
export function usePurchasesByItems(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.PURCHASES_BY_ITEMS, query],
{
method: 'get',
url: '/financial_statements/purchases-by-items',
params: query,
},
{
select: (res) => ({
tableRows: purchasesByItemsReducer(res.data.data),
...res.data,
}),
defaultData: {
tableRows: [],
data: [],
query: {},
},
...props,
},
);
}
/**
* Retrieve sales by items.
*/
export function useSalesByItems(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.SALES_BY_ITEMS, query],
{
method: 'get',
url: '/financial_statements/sales-by-items',
params: query,
},
{
select: (res) => ({
tableRows: salesByItemsReducer(res.data.data),
...res.data,
}),
defaultData: {
tableRows: [],
data: [],
query: {},
},
...props,
},
);
}
/**
* Retrieve customers balance summary report.
*/
export function useCustomerBalanceSummaryReport(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.CUSTOMERS_BALANCE_SUMMARY, query],
{
method: 'get',
url: '/financial_statements/customer-balance-summary',
params: query,
headers: {
Accept: 'application/json+table',
},
},
{
select: (res) => ({
columns: res.data.columns,
query: res.data.query,
tableRows: res.data.table.rows,
}),
defaultData: {
tableRows: [],
query: {},
},
...props,
},
);
}
/**
* Retrieve vendors balance summary report.
*/
export function useVendorsBalanceSummaryReport(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.VENDORS_BALANCE_SUMMARY, query],
{
method: 'get',
url: '/financial_statements/vendor-balance-summary',
params: query,
headers: {
Accept: 'application/json+table',
},
},
{
select: (res) => ({
columns: res.data.columns,
query: res.data.query,
tableRows: res.data.table.data,
}),
defaultData: {
tableRows: [],
query: {},
},
...props,
},
);
}
/**
* Retrieve customers transactions report.
*/
export function useCustomersTransactionsReport(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.CUSTOMERS_TRANSACTIONS, query],
{
method: 'get',
url: '/financial_statements/transactions-by-customers',
params: query,
headers: {
Accept: 'application/json+table',
},
},
{
select: (res) => ({
data: res.data.table,
tableRows: res.data.table.rows,
}),
defaultData: {
tableRows: [],
data: [],
},
...props,
},
);
}
/**
* Retrieve vendors transactions report.
*/
export function useVendorsTransactionsReport(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.VENDORS_TRANSACTIONS, query],
{
method: 'get',
url: '/financial_statements/transactions-by-vendors',
params: query,
headers: {
Accept: 'application/json+table',
},
},
{
select: (res) => ({
data: res.data.table,
tableRows: res.data.table.data,
}),
defaultData: {
tableRows: [],
data: [],
},
...props,
},
);
}
/**
* Retrieve cash flow statement report.
*/
export function useCashFlowStatementReport(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.CASH_FLOW_STATEMENT, query],
{
method: 'get',
url: '/financial_statements/cash-flow',
params: query,
headers: {
Accept: 'application/json+table',
},
},
{
select: (res) => ({
columns: res.data.table.columns,
query: res.data.query,
meta: res.data.meta,
tableRows: res.data.table.data,
}),
defaultData: {
tableRows: [],
columns: [],
query: {},
meta: {},
},
...props,
},
);
}
/**
* Retrieve inventory item detail report.
*/
export function useInventoryItemDetailsReport(query, props) {
return useRequestQuery(
[t.FINANCIAL_REPORT, t.INVENTORY_ITEM_DETAILS, query],
{
method: 'get',
url: '/financial_statements/inventory-item-details',
params: query,
headers: {
Accept: 'application/json+table',
},
},
{
select: (res) => ({
columns: res.data.table.columns,
query: res.data.query,
meta: res.data.meta,
tableRows: res.data.table.data,
}),
defaultData: {
tableRows: [],
columns: [],
query: {},
meta: {},
},
...props,
},
);
}
/**
* Retrieve transactions by reference report.
*/
export function useTransactionsByReference(query, props) {
return useRequestQuery(
[t.TRANSACTIONS_BY_REFERENCE, query],
{
method: 'get',
url: `/financial_statements/transactions-by-reference`,
params: query,
},
{
select: (res) => res.data,
defaultData: {
transactions: [],
},
...props,
},
);
}

30
src/hooks/query/index.js Normal file
View File

@@ -0,0 +1,30 @@
export * from './authentication';
export * from './accounts';
export * from './views';
export * from './items';
export * from './itemsCategories';
export * from './inventoryAdjustments';
export * from './expenses';
export * from './financialReports';
export * from './customers';
export * from './vendors';
export * from './manualJournals';
export * from './currencies';
export * from './invoices';
export * from './bills';
export * from './estimates';
export * from './receipts';
export * from './paymentReceives';
export * from './paymentMades';
export * from './settings';
export * from './users';
export * from './invite';
export * from './exchangeRates';
export * from './contacts';
export * from './subscriptions';
export * from './organization';
export * from './landedCost';
export * from './UniversalSearch/UniversalSearch';
export * from './GenericResource';
export * from './jobs';
export * from './misc';

View File

@@ -0,0 +1,124 @@
import { useMutation, useQueryClient } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from 'utils';
import useApiRequest from '../useRequest';
import t from './types';
const commonInvalidateQueries = (queryClient) => {
// Invalidate inventory adjustments.
queryClient.invalidateQueries(t.INVENTORY_ADJUSTMENTS);
queryClient.invalidateQueries(t.INVENTORY_ADJUSTMENT);
// Invalidate items.
queryClient.invalidateQueries(t.ITEMS);
queryClient.invalidateQueries(t.ITEM);
// Invalidate accounts.
queryClient.invalidateQueries(t.ACCOUNTS);
queryClient.invalidateQueries(t.ACCOUNT);
// Invalidate financial reports.
queryClient.invalidateQueries(t.FINANCIAL_REPORT);
};
/**
* Creates the inventory adjustment to the given item.
*/
export function useCreateInventoryAdjustment(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
(values) => apiRequest.post('inventory_adjustments/quick', values),
{
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
},
);
}
/**
* Deletes the inventory adjustment transaction.
*/
export function useDeleteInventoryAdjustment(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`inventory_adjustments/${id}`), {
onSuccess: (res, id) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
const inventoryAdjustmentsTransformer = (response) => {
return {
transactions: response.data.inventoy_adjustments,
pagination: transformPagination(response.data.pagination),
};
};
/**
* Retrieve inventory adjustment list with pagination meta.
*/
export function useInventoryAdjustments(query, props) {
return useRequestQuery(
['INVENTORY_ADJUSTMENTS', query],
{ url: 'inventory_adjustments', params: query },
{
select: inventoryAdjustmentsTransformer,
defaultData: {
transactions: [],
pagination: {
page: 1,
pageSize: 12,
total: 0,
pagesCount: 0,
},
},
...props,
},
);
}
/**
* Publishes the given inventory adjustment.
*/
export function usePublishInventoryAdjustment(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
(id) => apiRequest.post(`inventory_adjustments/${id}/publish`),
{
onSuccess: (res, id) => {
// Invalidate specific inventory adjustment.
queryClient.invalidateQueries([t.INVENTORY_ADJUSTMENT, id]);
commonInvalidateQueries(queryClient);
},
...props,
},
);
}
/**
* Retrieve the inventory adjustment details.
* @param {number} id - inventory adjustment id.
*/
export function useInventoryAdjustment(id, props, requestProps) {
return useRequestQuery(
[t.INVENTORY_ADJUSTMENT, id],
{ method: 'get', url: `inventory_adjustments/${id}`, ...requestProps },
{
select: (res) => res.data.data,
defaultData: {},
...props,
},
);
}

40
src/hooks/query/invite.js Normal file
View File

@@ -0,0 +1,40 @@
import { useMutation } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest';
/**
* Authentication invite accept.
*/
export const useAuthInviteAccept = (props) => {
const apiRequest = useApiRequest();
return useMutation(
([values, token]) => apiRequest.post(`invite/accept/${token}`, values),
props,
);
}
/**
* Retrieve the invite meta by the given token.
* @param {string} token - Token.
*/
export const useInviteMetaByToken = (token, props) => {
return useRequestQuery(
['INVITE_META', token],
{ method: 'get', url: `invite/invited/${token}` },
{
select: (res) => res.data,
...props
}
);
}
export const useResendInvitation = (props) => {
const apiRequest = useApiRequest();
return useMutation(
(userId) => apiRequest.post(`invite/resend/${userId}`),
props
)
}

196
src/hooks/query/invoices.js Normal file
View File

@@ -0,0 +1,196 @@
import { useQueryClient, useMutation } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from 'utils';
import useApiRequest from '../useRequest';
import { useRequestPdf } from '../useRequestPdf';
import t from './types';
// Common invalidate queries.
const commonInvalidateQueries = (queryClient) => {
// Invalidate invoices.
queryClient.invalidateQueries(t.SALE_INVOICES);
// Invalidate customers.
queryClient.invalidateQueries(t.CUSTOMERS);
// Invalidate accounts.
queryClient.invalidateQueries(t.ITEMS);
queryClient.invalidateQueries(t.ITEM);
// Invalidate settings.
queryClient.invalidateQueries([t.SETTING, t.SETTING_INVOICES]);
// Invalidate financial reports.
queryClient.invalidateQueries(t.FINANCIAL_REPORT);
// Invalidate accounts.
queryClient.invalidateQueries(t.ACCOUNTS);
queryClient.invalidateQueries(t.ACCOUNT);
};
/**
* Creates a new sale invoice.
*/
export function useCreateInvoice(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('sales/invoices', values), {
onSuccess: (res, values) => {
// Invalidate invoice customer.
queryClient.invalidateQueries([t.CUSTOMER, values.customer_id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Edits the given sale invoice.
*/
export function useEditInvoice(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`sales/invoices/${id}`, values),
{
onSuccess: (res, [id, values]) => {
// Invalidate specific sale invoice.
queryClient.invalidateQueries([t.SALE_INVOICE, id]);
// Invalidate invoice customer.
queryClient.invalidateQueries([t.CUSTOMER, values.customer_id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
},
);
}
/**
* Deletes the given sale invoice.
*/
export function useDeleteInvoice(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`sales/invoices/${id}`), {
onSuccess: (res, id) => {
// Invalidate specific invoice.
queryClient.invalidateQueries([t.SALE_INVOICE, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
const transformInvoices = (res) => ({
invoices: res.data.sales_invoices,
pagination: transformPagination(res.data.pagination),
filterMeta: res.data.filter_meta,
});
/**
* Retrieve sale invoices list with pagination meta.
*/
export function useInvoices(query, props) {
return useRequestQuery(
[t.SALE_INVOICES, query],
{ method: 'get', url: 'sales/invoices', params: query },
{
select: transformInvoices,
defaultData: {
invoices: [],
pagination: {
page: 1,
pageSize: 12,
total: 0,
},
filterMeta: {},
},
...props,
},
);
}
/**
* Marks the sale invoice as delivered.
*/
export function useDeliverInvoice(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
(invoiceId) => apiRequest.post(`sales/invoices/${invoiceId}/deliver`),
{
onSuccess: (res, invoiceId) => {
// Invalidate specific invoice.
queryClient.invalidateQueries([t.SALE_INVOICE, invoiceId]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
},
);
}
/**
* Retrieve the sale invoice details.
* @param {number} invoiceId - Invoice id.
*/
export function useInvoice(invoiceId, props, requestProps) {
return useRequestQuery(
[t.SALE_INVOICE, invoiceId],
{ method: 'get', url: `sales/invoices/${invoiceId}`, ...requestProps },
{
select: (res) => res.data.sale_invoice,
defaultData: {},
...props,
},
);
}
/**
* Retrieve the invoice pdf document data.
*/
export function usePdfInvoice(invoiceId) {
return useRequestPdf(`sales/invoices/${invoiceId}`);
}
/**
* Retrieve due invoices of the given customer id.
* @param {number} customerId - Customer id.
*/
export function useDueInvoices(customerId, props) {
return useRequestQuery(
[t.SALE_INVOICES, t.SALE_INVOICES_DUE, customerId],
{
method: 'get',
url: `sales/invoices/payable`,
params: { customer_id: customerId },
},
{
select: (res) => res.data.sales_invoices,
defaultData: [],
...props,
},
);
}
export function useRefreshInvoices() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries(t.SALE_INVOICES);
},
};
}

172
src/hooks/query/items.js Normal file
View File

@@ -0,0 +1,172 @@
import { useMutation, useQueryClient } from 'react-query';
import { transformPagination, transformResponse } from 'utils';
import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest';
import t from './types';
const DEFAULT_PAGINATION = {
pageSize: 12,
page: 0,
pagesCount: 0,
};
// Common invalidate queries.
const commonInvalidateQueries = (queryClient) => {
// Invalidate items.
queryClient.invalidateQueries(t.ITEMS);
// Invalidate items categories.
queryClient.invalidateQueries(t.ITEMS_CATEGORIES);
};
/**
* Creates a new item.
*/
export function useCreateItem(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('items', values), {
onSuccess: (res, values) => {
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Edits the given item.
*/
export function useEditItem(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(([id, values]) => apiRequest.post(`items/${id}`, values), {
onSuccess: (res, [id, values]) => {
// Invalidate specific item.
queryClient.invalidateQueries([t.ITEM, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Deletes the given item.
*/
export function useDeleteItem(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`items/${id}`), {
onSuccess: (res, id) => {
// Invalidate specific item.
queryClient.invalidateQueries([t.ITEM, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Activate the given item.
*/
export function useActivateItem(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`items/${id}/activate`), {
onSuccess: (res, id) => {
// Invalidate specific item.
queryClient.invalidateQueries([t.ITEM, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Inactivate the given item.
*/
export function useInactivateItem(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`items/${id}/inactivate`), {
onSuccess: (res, id) => {
// Invalidate specific item.
queryClient.invalidateQueries([t.ITEM, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
// Transformes items response.
const transformItemsResponse = (response) => {
return {
items: response.data.items,
pagination: transformPagination(transformResponse(response.data.pagination)),
filterMeta: transformResponse(response.data.filter_meta),
};
};
/**
* Retrieves items list.
*/
export function useItems(query, props) {
return useRequestQuery(
[t.ITEMS, query],
{
method: 'get',
url: 'items',
params: { ...query },
},
{
select: transformItemsResponse,
defaultData: {
items: [],
pagination: DEFAULT_PAGINATION,
filterMeta: {},
},
...props
}
);
}
export function useRefreshItems() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries(t.ITEMS);
},
}
}
/**
* Retrieve details of the given item.
* @param {number} id - Item id.
*/
export function useItem(id, props) {
return useRequestQuery(
[t.ITEM, id],
{
method: 'get',
url: `items/${id}`,
},
{
select: (response) => response.data.item,
defaultData: {},
...props
},
);
}

View File

@@ -0,0 +1,109 @@
import { useMutation, useQueryClient } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest';
import t from './types';
const commonInvalidateQueries = (queryClient) => {
// Invalidate items categories.
queryClient.invalidateQueries(t.ITEMS_CATEGORIES);
// Invalidate items.
queryClient.invalidateQueries(t.ITEMS);
};
/**
* Creates a new item category.
*/
export function useCreateItemCategory(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('item_categories', values), {
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Edits the item category.
*/
export function useEditItemCategory(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`item_categories/${id}`, values),
{
onSuccess: (res, [id, values]) => {
// Invalidate specific item category.
queryClient.invalidateQueries([t.ITEM_CATEGORY, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
},
);
}
/**
* Deletes the given item category.
*/
export function useDeleteItemCategory(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`item_categories/${id}`), {
onSuccess: (res, id) => {
// Invalidate specific item category.
queryClient.invalidateQueries([t.ITEM_CATEGORY, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
const transformCategories = (res) => ({
itemsCategories: res.data.item_categories,
pagination: res.data.pagination,
});
/**
* Retrieve the items categories.
*/
export function useItemsCategories(query, props) {
return useRequestQuery(
[t.ITEMS_CATEGORIES, query],
{ method: 'get', url: `item_categories`, params: query },
{
select: transformCategories,
defaultData: {
itemsCategories: [],
pagination: {}
},
...props,
},
);
}
/**
* Retrieve the item category details.
* @param {number} id - Item category.
*/
export function useItemCategory(id, props) {
return useRequestQuery(
[t.ITEM_CATEGORY, id],
{ method: 'get', url: `item_categories/${id}` },
{
select: (res) => res.data.category,
defaultData: {},
...props,
},
);
}

16
src/hooks/query/jobs.js Normal file
View File

@@ -0,0 +1,16 @@
import { useRequestQuery } from '../useQueryRequest';
/**
* Retrieve the job metadata.
*/
export function useJob(jobId, props = {}) {
return useRequestQuery(
['JOB', jobId],
{ method: 'get', url: `jobs/${jobId}` },
{
select: (res) => res.data.job,
defaultData: {},
...props,
},
);
}

View File

@@ -0,0 +1,90 @@
import { useQueryClient, useMutation } from 'react-query';
import useApiRequest from '../useRequest';
import { useRequestQuery } from '../useQueryRequest';
import t from './types';
const commonInvalidateQueries = (queryClient) => {
// Invalidate bills.
queryClient.invalidateQueries(t.BILLS);
queryClient.invalidateQueries(t.BILL);
// Invalidate landed cost.
queryClient.invalidateQueries(t.LANDED_COST);
queryClient.invalidateQueries(t.LANDED_COST_TRANSACTION);
};
/**
* Creates a new landed cost.
*/
export function useCreateLandedCost(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) =>
apiRequest.post(`purchases/landed-cost/bills/${id}/allocate`, values),
{
onSuccess: (res, id) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
},
);
}
/**
* Deletes the given landed cost.
*/
export function useDeleteLandedCost(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
(landedCostId) =>
apiRequest.delete(`purchases/landed-cost/${landedCostId}`),
{
onSuccess: (res, id) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
},
);
}
/**
* Retrieve the landed cost transactions.
*/
export function useLandedCostTransaction(query, props) {
return useRequestQuery(
[t.LANDED_COST, query],
{
method: 'get',
url: 'purchases/landed-cost/transactions',
params: { transaction_type: query },
},
{
select: (res) => res.data,
defaultData: {
transactions: [],
},
...props,
},
);
}
/**
* Retrieve the bill located landed cost transactions.
*/
export function useBillLocatedLandedCost(id, props) {
return useRequestQuery(
[t.LANDED_COST_TRANSACTION, id],
{ method: 'get', url: `purchases/landed-cost/bills/${id}/transactions` },
{
select: (res) => res.data.transactions,
defaultData: {},
...props,
},
);
}

View File

@@ -0,0 +1,149 @@
import { useMutation, useQueryClient } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from 'utils';
import useApiRequest from '../useRequest';
import t from './types';
const commonInvalidateQueries = (client) => {
// Invalidate manual journals.
client.invalidateQueries(t.MANUAL_JOURNALS);
// Invalidate customers.
client.invalidateQueries(t.CUSTOMERS);
client.invalidateQueries(t.CUSTOMER);
// Invalidate vendors.
client.invalidateQueries(t.VENDORS);
client.invalidateQueries(t.VENDOR);
// Invalidate accounts.
client.invalidateQueries(t.ACCOUNTS);
client.invalidateQueries(t.ACCOUNT);
// Invalidate financial reports.
client.invalidateQueries(t.FINANCIAL_REPORT);
};
/**
* Creates a new manual journal.
*/
export function useCreateJournal(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('manual-journals', values), {
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Edits the given manual journal.
*/
export function useEditJournal(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`manual-journals/${id}`, values),
{
onSuccess: (res, [id]) => {
// Invalidate specific manual journal.
queryClient.invalidateQueries(t.MANUAL_JOURNAL, id);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
},
);
}
/**
* Deletes the given manual jouranl.
*/
export function useDeleteJournal(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`manual-journals/${id}`), {
onSuccess: (res, id) => {
// Invalidate specific manual journal.
queryClient.invalidateQueries(t.MANUAL_JOURNAL, id);
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Publishes the given manual journal.
*/
export function usePublishJournal(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`manual-journals/${id}/publish`), {
onSuccess: (res, id) => {
// Invalidate specific manual journal.
queryClient.invalidateQueries(t.MANUAL_JOURNAL, id);
commonInvalidateQueries(queryClient);
},
...props,
});
}
const transformJournals = (response) => ({
manualJournals: response.data.manual_journals,
pagination: transformPagination(response.data.pagination),
filterMeta: response.data.filter_meta,
});
/**
* Retrieve the manual journals with pagination meta.
*/
export function useJournals(query, props) {
return useRequestQuery(
[t.MANUAL_JOURNALS, query],
{ method: 'get', url: 'manual-journals', params: query },
{
select: transformJournals,
defaultData: {
manualJournals: [],
pagination: {},
filterMeta: {},
},
...props,
},
);
}
/**
* Retrieve the manual journal details.
*/
export function useJournal(id, props) {
return useRequestQuery(
[t.MANUAL_JOURNAL, id],
{ method: 'get', url: `manual-journals/${id}` },
{
select: (res) => res.data.manual_journal,
defaultData: {},
...props,
},
);
}
export function useRefreshJournals() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries(t.MANUAL_JOURNALS);
},
};
}

16
src/hooks/query/misc.js Normal file
View File

@@ -0,0 +1,16 @@
import { useRequestQuery } from '../useQueryRequest';
/**
* Retrieve the job metadata.
*/
export function useDateFormats(props = {}) {
return useRequestQuery(
['DATE_FORMATS'],
{ method: 'get', url: `/date_formats` },
{
select: (res) => res.data.data,
defaultData: [],
...props,
},
);
}

View File

@@ -0,0 +1,105 @@
import { useMutation, useQueryClient } from 'react-query';
import { batch } from 'react-redux';
import t from './types';
import useApiRequest from '../useRequest';
import { useRequestQuery } from '../useQueryRequest';
import { useSetOrganizations, useSetSubscriptions } from '../state';
import { omit } from 'lodash';
/**
* Retrieve organizations of the authenticated user.
*/
export function useOrganizations(props) {
return useRequestQuery(
[t.ORGANIZATIONS],
{ method: 'get', url: `organization/all` },
{
select: (res) => res.data.organizations,
initialDataUpdatedAt: 0,
initialData: {
data: {
organizations: [],
},
},
...props,
},
);
}
/**
* Retrieve the current organization metadata.
*/
export function useCurrentOrganization(props) {
const setOrganizations = useSetOrganizations();
const setSubscriptions = useSetSubscriptions();
return useRequestQuery(
[t.ORGANIZATION_CURRENT],
{ method: 'get', url: `organization` },
{
select: (res) => res.data.organization,
defaultData: {},
onSuccess: (data) => {
const organization = omit(data, ['subscriptions']);
batch(() => {
// Sets subscriptions.
setSubscriptions(data.subscriptions);
// Sets organizations.
setOrganizations([organization]);
});
},
...props,
},
);
}
/**
* Organization setup.
*/
export function useOrganizationSetup() {
const apiRequest = useApiRequest();
const queryClient = useQueryClient();
return useMutation(
(values) => apiRequest.post(`organization/build`, values),
{
onSuccess: (res) => {
queryClient.invalidateQueries(t.ORGANIZATION_CURRENT);
queryClient.invalidateQueries(t.ORGANIZATIONS);
},
},
);
}
/**
* Saves the settings.
*/
export function useUpdateOrganization(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
(information) => apiRequest.put('organization', information),
{
onSuccess: () => {
queryClient.invalidateQueries(t.ORGANIZATION_CURRENT);
queryClient.invalidateQueries(t.ORGANIZATIONS);
},
...props,
},
);
}
export function useOrgBaseCurrencyMutateAbilities(props) {
return useRequestQuery(
[t.ORGANIZATION_MUTATE_BASE_CURRENCY_ABILITIES],
{ method: 'get', url: `organization/base_currency_mutate` },
{
select: (res) => res.data.abilities,
defaultData: [],
...props,
},
);
}

View File

@@ -0,0 +1,185 @@
import { useMutation, useQueryClient } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from 'utils';
import useApiRequest from '../useRequest';
import t from './types';
const commonInvalidateQueries = (client) => {
// Invalidate payment mades.
client.invalidateQueries(t.PAYMENT_MADES);
// Invalidate payment made new entries.
client.invalidateQueries(t.PAYMENT_MADE_NEW_ENTRIES);
client.invalidateQueries(t.PAYMENT_MADE_EDIT_PAGE);
// Invalidate financial reports.
client.invalidateQueries(t.FINANCIAL_REPORT);
// Invalidate accounts.
client.invalidateQueries(t.ACCOUNTS);
client.invalidateQueries(t.ACCOUNT);
// Invalidate bills.
client.invalidateQueries(t.BILLS);
client.invalidateQueries(t.BILL);
// Invalidate vendors.
client.invalidateQueries(t.VENDORS);
client.invalidateQueries(t.VENDOR);
};
/**
* Retrieve payment mades list.
*/
export function usePaymentMades(query, props) {
return useRequestQuery(
[t.PAYMENT_MADES, query],
{ url: 'purchases/bill_payments', params: query },
{
select: (res) => ({
paymentMades: res.data.bill_payments,
pagination: transformPagination(res.data.pagination),
filterMeta: res.data.filter_meta,
}),
defaultData: {
paymentMades: [],
pagination: {},
filterMeta: {},
},
...props,
},
);
}
/**
* Creates payment made.
*/
export function useCreatePaymentMade(props) {
const client = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
(values) => apiRequest.post('purchases/bill_payments', values),
{
onSuccess: (res, values) => {
// Common invalidation queries.
commonInvalidateQueries(client);
},
...props,
},
);
}
/**
* Edits payment made.
*/
export function useEditPaymentMade(props) {
const client = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`purchases/bill_payments/${id}`, values),
{
onSuccess: (res, [id, values]) => {
// Common invalidation queries.
commonInvalidateQueries(client);
// Invalidate specific payment made.
client.invalidateQueries([t.PAYMENT_MADE, id]);
},
...props,
},
);
}
/**
* Deletes payment made.
*/
export function useDeletePaymentMade(props) {
const client = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
(id) => apiRequest.delete(`purchases/bill_payments/${id}`),
{
onSuccess: (res, id) => {
// Common invalidation queries.
commonInvalidateQueries(client);
// Invalidate specific payment made.
client.invalidateQueries([t.PAYMENT_MADE, id]);
},
...props,
},
);
}
/**
* Retrieve specific payment made.
*/
export function usePaymentMadeEditPage(id, props) {
return useRequestQuery(
[t.PAYMENT_MADE_EDIT_PAGE, id],
{
method: 'get',
url: `purchases/bill_payments/${id}/edit-page`,
},
{
select: (res) => ({
paymentMade: res.data.bill_payment,
entries: res.data.entries,
}),
defaultData: {
paymentMade: {},
entries: [],
},
...props,
},
);
}
/**
* Retreive payment made new page entries.
* @param {number} vendorId -
*/
export function usePaymentMadeNewPageEntries(vendorId, props) {
return useRequestQuery(
[t.PAYMENT_MADE_NEW_ENTRIES, vendorId],
{
method: 'get',
url: `purchases/bill_payments/new-page/entries`,
params: { vendor_id: vendorId },
},
{
select: (res) => res.data.entries,
defaultData: [],
...props,
},
);
}
export function useRefreshPaymentMades() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries(t.PAYMENT_MADES);
},
};
}
/**
* Retrieve specific payment made.
* @param {number} id - Payment made.
*/
export function usePaymentMade(id, props) {
return useRequestQuery(
[t.PAYMENT_MADE, id],
{ method: 'get', url: `purchases/bill_payments/${id}` },
{
select: (res) => res.data.bill_payment,
defaultData: {},
...props,
},
);
}

View File

@@ -0,0 +1,172 @@
import { useMutation, useQueryClient } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest';
import { transformPagination, saveInvoke } from 'utils';
import t from './types';
// Common invalidate queries.
const commonInvalidateQueries = (client) => {
// Invalidate payment receives.
client.invalidateQueries(t.PAYMENT_RECEIVES);
client.invalidateQueries(t.PAYMENT_RECEIVE_EDIT_PAGE);
// Invalidate invoices.
client.invalidateQueries(t.SALE_INVOICES);
client.invalidateQueries(t.SALE_INVOICE);
// Invalidate accounts.
client.invalidateQueries(t.ACCOUNTS);
client.invalidateQueries(t.ACCOUNT);
// Invalidate financial reports.
client.invalidateQueries(t.FINANCIAL_REPORT);
// Invalidate customers.
client.invalidateQueries(t.CUSTOMERS);
client.invalidateQueries(t.CUSTOMER);
};
// Transform payment receives.
const transformPaymentReceives = (res) => ({
paymentReceives: res.data.payment_receives,
pagination: transformPagination(res.data.pagination),
filterMeta: res.data.filter_meta,
});
/**
* Retrieve accounts list.
*/
export function usePaymentReceives(query, props) {
return useRequestQuery(
[t.PAYMENT_RECEIVES, query],
{ method: 'get', url: 'sales/payment_receives', params: query },
{
select: transformPaymentReceives,
defaultData: {
paymentReceives: [],
pagination: { page: 1, pageSize: 12, total: 0 },
filterMeta: {},
},
...props,
},
);
}
/**
* Creates payment receive.
*/
export function useCreatePaymentReceive(props) {
const client = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
(values) => apiRequest.post('sales/payment_receives', values),
{
onSuccess: (data, values) => {
// Invalidate specific payment receive.
commonInvalidateQueries(client);
// Invalidate payment receive settings.
client.invalidateQueries([t.SETTING, t.SETTING_PAYMENT_RECEIVES]);
saveInvoke(props?.onSuccess, data);
},
...props,
},
);
}
/**
* Edits payment receive.
*/
export function useEditPaymentReceive(props) {
const client = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`sales/payment_receives/${id}`, values),
{
onSuccess: (data, [id, values]) => {
// Invalidate specific payment receive.
client.invalidateQueries([t.PAYMENT_RECEIVE, id]);
// Common invalidate queries.
commonInvalidateQueries(client);
saveInvoke(props?.onSuccess, data);
},
...props,
},
);
}
/**
* Deletes payment receive.
*/
export function useDeletePaymentReceive(props) {
const client = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
(id) => apiRequest.delete(`sales/payment_receives/${id}`),
{
onSuccess: (data, id) => {
// Invalidate specific payment receive.
client.invalidateQueries([t.PAYMENT_RECEIVE, id]);
commonInvalidateQueries(client);
saveInvoke(props?.onSuccess, data);
},
...props,
},
);
}
/**
* Retrieve specific payment receive.
* @param {number} id - Payment receive.
*/
export function usePaymentReceive(id, props) {
return useRequestQuery(
[t.PAYMENT_RECEIVE, id],
{ method: 'get', url: `sales/payment_receives/${id}` },
{
select: (res) => res.data.payment_receive,
defaultData: {},
...props,
},
);
}
/**
* Retrieve information of payment receive in edit page.
* @param {number} id - Payment receive id.
*/
export function usePaymentReceiveEditPage(id, props) {
return useRequestQuery(
[t.PAYMENT_RECEIVE_EDIT_PAGE, id],
{ method: 'get', url: `sales/payment_receives/${id}/edit-page` },
{
select: (res) => ({
paymentReceive: res.data.payment_receive,
entries: res.data.entries,
}),
defaultData: {
paymentReceive: {},
entries: [],
},
...props,
},
);
}
export function useRefreshPaymentReceive() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries(t.PAYMENT_RECEIVES);
},
};
}

161
src/hooks/query/receipts.js Normal file
View File

@@ -0,0 +1,161 @@
import { useQueryClient, useMutation } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import { useRequestPdf } from '../useRequestPdf';
import useApiRequest from '../useRequest';
import { transformPagination } from 'utils';
import t from './types';
const commonInvalidateQueries = (queryClient) => {
// Invalidate receipts.
queryClient.invalidateQueries(t.SALE_RECEIPTS);
// Invalidate accounts.
queryClient.invalidateQueries(t.ITEMS);
queryClient.invalidateQueries(t.ITEM);
// Invalidate accounts.
queryClient.invalidateQueries(t.ACCOUNTS);
queryClient.invalidateQueries(t.ACCOUNT);
// Invalidate financial reports.
queryClient.invalidateQueries(t.FINANCIAL_REPORT);
// Invalidate the settings.
queryClient.invalidateQueries([t.SETTING, t.SETTING_RECEIPTS]);
};
/**
* Creates a new sale invoice.
*/
export function useCreateReceipt(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('sales/receipts', values), {
onSuccess: () => {
// Invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Edits the given sale invoice.
*/
export function useEditReceipt(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`sales/receipts/${id}`, values),
{
onSuccess: (res, [id, values]) => {
// Invalidate specific receipt.
queryClient.invalidateQueries([t.SALE_RECEIPT, id]);
// Invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
},
);
}
/**
* Deletes the given sale invoice.
*/
export function useDeleteReceipt(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`sales/receipts/${id}`), {
onSuccess: (res, id) => {
// Invalidate specific receipt.
queryClient.invalidateQueries([t.SALE_RECEIPT, id]);
// Invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Deletes the given sale invoice.
*/
export function useCloseReceipt(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.post(`sales/receipts/${id}/close`), {
onSuccess: (res, id) => {
queryClient.invalidateQueries([t.SALE_RECEIPT, id]);
// Invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
const transformReceipts = (res) => ({
receipts: res.data.data,
pagination: transformPagination(res.data.pagination),
filterMeta: res.data.filter_meta,
});
/**
* Retrieve sale invoices list with pagination meta.
*/
export function useReceipts(query, props) {
return useRequestQuery(
['SALE_RECEIPTS', query],
{ method: 'get', url: 'sales/receipts', params: query },
{
select: transformReceipts,
defaultData: {
receipts: [],
pagination: {
page: 1,
page_size: 12,
total: 0,
},
filterMeta: {},
},
...props,
},
);
}
/**
* Retrieve sale invoices list with pagination meta.
*/
export function useReceipt(id, props) {
return useRequestQuery(
['SALE_RECEIPT', id],
{ method: 'get', url: `sales/receipts/${id}` },
{
select: (res) => res.data.sale_receipt,
defaultData: {},
...props,
},
);
}
/**
* Retrieve the receipt pdf document data.
*/
export function usePdfReceipt(ReceiptId) {
return useRequestPdf(`sales/receipts/${ReceiptId}`);
}
export function useRefreshReceipts() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries(t.SALE_RECEIPTS);
},
};
}

114
src/hooks/query/settings.js Normal file
View File

@@ -0,0 +1,114 @@
import { useEffect } from 'react';
import { useMutation, useQueryClient } from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest';
import { useSetSettings } from 'hooks/state';
import t from './types';
/**
* Saves the settings.
*/
export function useSaveSettings(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((settings) => apiRequest.post('settings', settings), {
onSuccess: () => {
queryClient.invalidateQueries(t.SETTING);
},
...props,
});
}
function useSettingsQuery(key, query, props) {
const setSettings = useSetSettings();
return useRequestQuery(
key,
{ method: 'get', url: 'settings', params: query },
{
select: (res) => res.data.settings,
defaultData: [],
onSuccess: (settings) => {
setSettings(settings);
},
...props,
},
);
}
/**
* Retrieve the all settings of the organization.
*/
export function useSettings() {
return useSettingsQuery([t.SETTING, 'ALL'], {});
}
/**
* Retrieve invoices settings.
*/
export function useSettingsInvoices(props) {
return useSettingsQuery(
[t.SETTING, t.SETTING_INVOICES],
{ group: 'sale_invoices' },
props,
);
}
/**
* Retrieve invoices settings.
*/
export function useSettingsEstimates(props) {
return useSettingsQuery(
[t.SETTING, t.SETTING_ESTIMATES],
{ group: 'sale_estimates' },
props,
);
}
/**
* Retrieve payment receives settings.
*/
export function useSettingsPaymentReceives(props) {
return useSettingsQuery(
[t.SETTING, t.SETTING_PAYMENT_RECEIVES],
{ group: 'payment_receives' },
props,
);
}
/**
* Retrieve sale receipts settings.
* @param {*} props
*/
export function useSettingsReceipts(props) {
return useSettingsQuery(
[t.SETTING, t.SETTING_RECEIPTS],
{ group: 'sale_receipts' },
props,
);
}
/**
* Retrieve sale receipts settings.
* @param {*} props
*/
export function useSettingsManualJournals(props) {
return useSettingsQuery(
[t.SETTING, t.SETTING_MANUAL_JOURNALS],
{ group: 'sale_receipts' },
props,
);
}
/**
* Retrieve sale receipts settings.
* @param {*} props
*/
export function useSettingsItems(props) {
return useSettingsQuery(
[t.SETTING, t.SETTING_ITEMS],
{ group: 'items' },
props,
);
}

View File

@@ -0,0 +1,44 @@
import { useEffect } from "react"
import { useMutation, useQueryClient } from "react-query";
import { useRequestQuery } from "../useQueryRequest";
import useApiRequest from "../useRequest";
import { useSetSubscriptions } from '../state/subscriptions';
import T from './types';
/**
* Subscription payment via voucher.
*/
export const usePaymentByVoucher = (props) => {
const apiRequest = useApiRequest();
const queryClient = useQueryClient();
return useMutation(
(values) => apiRequest.post('subscription/license/payment', values),
{
onSuccess: () => {
queryClient.invalidateQueries(T.SUBSCRIPTIONS);
queryClient.invalidateQueries(T.ORGANIZATION_CURRENT);
queryClient.invalidateQueries(T.ORGANIZATIONS);
},
...props,
}
);
}
/**
* Fetches the organization subscriptions.
*/
export const useOrganizationSubscriptions = (props) => {
const setSubscriptions = useSetSubscriptions();
const state = useRequestQuery(
[T.SUBSCRIPTIONS],
{ method: 'get', url: 'subscriptions' },
{ ...props },
);
useEffect(() => {
if (state.isSuccess) {
setSubscriptions(state.data);
}
}, [state.isSuccess, state.data, setSubscriptions])
};

157
src/hooks/query/types.js Normal file
View File

@@ -0,0 +1,157 @@
const ACCOUNTS = {
ACCOUNT: 'ACCOUNT',
ACCOUNT_TRANSACTION: 'ACCOUNT_TRANSACTION',
ACCOUNTS: 'ACCOUNTS',
ACCOUNTS_TYPES: 'ACCOUNTS_TYPES',
};
const FINANCIAL_REPORTS = {
FINANCIAL_REPORT: 'FINANCIAL-REPORT',
BALANCE_SHEET: 'BALANCE-SHEET',
TRIAL_BALANCE_SHEET: 'TRIAL-BALANCE-SHEET',
PROFIT_LOSS_SHEET: 'PROFIT-LOSS-SHEET',
GENERAL_LEDGER: 'GENERAL-LEDGER',
JOURNAL: 'JOURNAL',
AR_AGING_SUMMARY: 'AR-AGING-SUMMARY',
AP_AGING_SUMMARY: 'AP-AGING-SUMMARY',
VENDORS_TRANSACTIONS: 'VENDORS_TRANSACTIONS',
CUSTOMERS_TRANSACTIONS: 'CUSTOMERS_TRANSACTIONS',
VENDORS_BALANCE_SUMMARY: 'VENDORS_BALANCE_SUMMARY',
CUSTOMERS_BALANCE_SUMMARY: 'CUSTOMERS_BALANCE_SUMMARY',
SALES_BY_ITEMS: 'SALES_BY_ITEMS',
PURCHASES_BY_ITEMS: 'PURCHASES_BY_ITEMS',
INVENTORY_VALUATION: 'INVENTORY_VALUATION',
CASH_FLOW_STATEMENT: 'CASH_FLOW_STATEMENT',
INVENTORY_ITEM_DETAILS: 'INVENTORY_ITEM_DETAILS',
TRANSACTIONS_BY_REFERENCE: 'TRANSACTIONS_BY_REFERENCE',
};
const BILLS = {
BILLS: 'BILLS',
BILL: 'BILL',
BILLS_DUE: 'BILLS_DUE',
};
const VENDORS = {
VENDORS: 'VENDORS',
VENDOR: 'VENDOR',
};
const CUSTOMERS = {
CUSTOMERS: 'CUSTOMERS',
CUSTOMER: 'CUSTOMER',
};
const ITEMS = {
ITEMS: 'ITEMS',
ITEM: 'ITEM',
ITEMS_CATEGORIES: 'ITEMS_CATEGORIES',
};
const SALE_ESTIMATES = {
SALE_ESTIMATES: 'SALE_ESTIMATES',
SALE_ESTIMATE: 'SALE_ESTIMATE',
};
const SALE_RECEIPTS = {
SALE_RECEIPTS: 'SALE_RECEIPTS',
SALE_RECEIPT: 'SALE_RECEIPT',
};
const INVENTORY_ADJUSTMENTS = {
INVENTORY_ADJUSTMENTS: 'INVENTORY_ADJUSTMENTS',
INVENTORY_ADJUSTMENT: 'INVENTORY_ADJUSTMENT',
};
const CURRENCIES = {
CURRENCIES: 'CURRENCIES',
};
const PAYMENT_MADES = {
PAYMENT_MADES: 'PAYMENT_MADES',
PAYMENT_MADE: 'PAYMENT_MADE',
PAYMENT_MADE_NEW_ENTRIES: 'PAYMENT_MADE_NEW_ENTRIES',
PAYMENT_MADE_EDIT_PAGE: 'PAYMENT_MADE_EDIT_PAGE',
};
const PAYMENT_RECEIVES = {
PAYMENT_RECEIVES: 'PAYMENT_RECEIVES',
PAYMENT_RECEIVE: 'PAYMENT_RECEIVE',
PAYMENT_RECEIVE_NEW_ENTRIES: 'PAYMENT_RECEIVE_NEW_ENTRIES',
PAYMENT_RECEIVE_EDIT_PAGE: 'PAYMENT_RECEIVE_EDIT_PAGE',
};
const SALE_INVOICES = {
SALE_INVOICES: 'SALE_INVOICES',
SALE_INVOICE: 'SALE_INVOICE',
SALE_INVOICES_DUE: 'SALE_INVOICES_DUE',
};
const USERS = {
USERS: 'USERS',
USER: 'USER',
};
const SETTING = {
SETTING: 'SETTING',
SETTING_INVOICES: 'SETTING_INVOICES',
SETTING_ESTIMATES: 'SETTING_ESTIMATES',
SETTING_RECEIPTS: 'SETTING_RECEIPTS',
SETTING_PAYMENT_RECEIVES: 'SETTING_PAYMENT_RECEIVES',
SETTING_MANUAL_JOURNALS: 'SETTING_MANUAL_JOURNALS',
SETTING_ITEMS: 'SETTING_ITEMS'
};
const ORGANIZATIONS = {
ORGANIZATIONS: 'ORGANIZATIONS',
ORGANIZATION_CURRENT: 'ORGANIZATION_CURRENT',
};
const SUBSCRIPTIONS = {
SUBSCRIPTIONS: 'SUBSCRIPTIONS',
};
const EXPENSES = {
EXPENSES: 'EXPENSES',
EXPENSE: 'EXPENSE',
};
const MANUAL_JOURNALS = {
MANUAL_JOURNALS: 'MANUAL_JOURNALS',
MANUAL_JOURNAL: 'MANUAL_JOURNAL',
};
const LANDED_COSTS = {
LANDED_COST: 'LANDED_COST',
LANDED_COSTS: 'LANDED_COSTS',
LANDED_COST_TRANSACTION: 'LANDED_COST_TRANSACTION',
};
const CONTACTS = {
CONTACTS: 'CONTACTS',
CONTACT: 'CONTACT',
};
export default {
...ACCOUNTS,
...BILLS,
...VENDORS,
...CUSTOMERS,
...FINANCIAL_REPORTS,
...ITEMS,
...SALE_ESTIMATES,
...INVENTORY_ADJUSTMENTS,
...CURRENCIES,
...SALE_RECEIPTS,
...PAYMENT_MADES,
...PAYMENT_RECEIVES,
...SALE_INVOICES,
...USERS,
...SETTING,
...ORGANIZATIONS,
...SUBSCRIPTIONS,
...EXPENSES,
...MANUAL_JOURNALS,
...LANDED_COSTS,
...CONTACTS,
};

127
src/hooks/query/users.js Normal file
View File

@@ -0,0 +1,127 @@
import { useMutation, useQueryClient } from 'react-query';
import { useQueryTenant, useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest';
import t from './types';
// Common invalidate queries.
const commonInvalidateQueries = (queryClient) => {
queryClient.invalidateQueries(t.USERS);
};
/**
* Create a new invite user.
*/
export function useCreateInviteUser(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('invite/send', values), {
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Edits the given user.
*/
export function useEditUser(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(([id, values]) => apiRequest.post(`users/${id}`, values), {
onSuccess: (res, [id, values]) => {
queryClient.invalidateQueries([t.USER, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
export function useInactivateUser(props) {
const apiRequest = useApiRequest();
const queryClient = useQueryClient();
return useMutation((userId) => apiRequest.put(`users/${userId}/inactivate`), {
onSuccess: (res, userId) => {
queryClient.invalidateQueries([t.USER, userId]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
export function useActivateUser(props) {
const apiRequest = useApiRequest();
const queryClient = useQueryClient();
return useMutation((userId) => apiRequest.put(`users/${userId}/activate`), {
onSuccess: (res, userId) => {
queryClient.invalidateQueries([t.USER, userId]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Deletes the given user.
*/
export function useDeleteUser(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`users/${id}`), {
onSuccess: (res, id) => {
queryClient.invalidateQueries([t.USER, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Retrieves users list.
*/
export function useUsers(props) {
return useRequestQuery(
[t.USERS],
{
method: 'get',
url: 'users',
},
{
select: (res) => res.data.users,
defaultData: [],
...props,
},
);
}
/**
* Retrieve details of the given user.
*/
export function useUser(id, props) {
return useRequestQuery(
[t.USER, id],
{
method: 'get',
url: `users/${id}`,
},
{
select: (response) => response.data.user,
defaultData: {},
...props,
},
);
}

126
src/hooks/query/vendors.js Normal file
View File

@@ -0,0 +1,126 @@
import { useMutation, useQueryClient } from 'react-query';
import t from './types';
import { transformPagination } from 'utils';
import useApiRequest from '../useRequest';
import { useRequestQuery } from '../useQueryRequest';
// Common invalidate queries.
const commonInvalidateQueries = (queryClient) => {
// Invalidate vendors list.
queryClient.invalidateQueries(t.VENDORS);
// Invalidate financial reports.
queryClient.invalidateQueries(t.ACCOUNTS);
queryClient.invalidateQueries(t.ACCOUNT);
// Invalidate financial reports.
queryClient.invalidateQueries(t.FINANCIAL_REPORT);
};
// Transformes vendors response.
const transformVendorsResponse = (res) => ({
vendors: res.data.vendors,
pagination: transformPagination(res.data.pagination),
filterMeta: res.data.filter_meta,
});
/**
* Retrieve vendors list.
*/
export function useVendors(query, props) {
return useRequestQuery(
[t.VENDORS, query],
{ method: 'get', url: `vendors`, params: query },
{
select: transformVendorsResponse,
defaultData: {
vendors: [],
pagination: {},
filterMeta: {},
},
...props,
},
);
}
/**
* Edits details of the given vendor.
*/
export function useEditVendor(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`vendors/${id}`, values),
{
onSuccess: (res, [id, values]) => {
// Invalidate specific vendor.
queryClient.invalidateQueries([t.VENDOR, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
},
);
}
/**
* Deletes the given vendor.
*/
export function useDeleteVendor(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((id) => apiRequest.delete(`vendors/${id}`), {
onSuccess: (res, id) => {
// Invalidate specific vendor.
queryClient.invalidateQueries([t.VENDOR, id]);
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Creates a new vendor.
*/
export function useCreateVendor(props) {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation((values) => apiRequest.post('vendors', values), {
onSuccess: () => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
});
}
/**
* Retrieve vendor details.
*/
export function useVendor(id, props) {
return useRequestQuery(
[t.VENDOR, id],
{ method: 'get', url: `vendors/${id}` },
{
select: (res) => res.data.vendor,
defaultData: {},
...props,
},
);
}
export function useRefreshVendors() {
const queryClient = useQueryClient();
return {
refresh: () => {
queryClient.invalidateQueries(t.VENDORS);
},
};
}

34
src/hooks/query/views.js Normal file
View File

@@ -0,0 +1,34 @@
import { useRequestQuery } from '../useQueryRequest';
/**
* Retrieve the resource views.
* @param {string} resourceSlug - Resource slug.
*/
export function useResourceViews(resourceSlug) {
return useRequestQuery(
['RESOURCE_VIEW', resourceSlug],
{ method: 'get', url: `views/resource/${resourceSlug}` },
{
select: (response) => response.data.views,
defaultData: [],
},
);
}
/**
* Retrieve the resource meta.
* @param {string} resourceSlug - Resource slug.
*/
export function useResourceMeta(resourceSlug, props) {
return useRequestQuery(
['RESOURCE_META', resourceSlug],
{ method: 'get', url: `resources/${resourceSlug}/meta` },
{
select: (res) => res.data.resource_meta,
defaultData: {
fields: {},
},
},
props,
);
}

View File

@@ -0,0 +1,36 @@
import {useState} from 'react';
const useStackableState = (initialState = []) => {
const [stackableState, setStackableState] = useState(initialState);
const indexState = (state) => stackableState.indexOf(state);
const hasState = (state) => indexState(state) !== -1;
const removeState = (state) => {
if (this.hasState(state)) {
const index = indexState(state);
const mutableState = [...stackableState];
mutableState.splice(index, 1);
setStackableState(mutableState);
}
};
const setState = (state) => {
if (!hasState(state)) {
setStackableState([
...stackableState,
state,
]);
}
};
return {
state: stackableState,
removeState,
indexState,
hasState,
setState,
};
};
export default useStackableState;

View File

@@ -0,0 +1,65 @@
import { useDispatch, useSelector } from 'react-redux';
import { useCallback } from 'react';
import { isAuthenticated } from 'store/authentication/authentication.reducer';
import {
setLogin,
setStoreReset,
} from 'store/authentication/authentication.actions';
import { useQueryClient } from 'react-query';
import { removeCookie } from '../../utils';
function removeAuthenticationCookies() {
removeCookie('token');
removeCookie('organization_id');
removeCookie('tenant_id');
removeCookie('authenticated_user_id');
removeCookie('locale');
}
export const useAuthActions = () => {
const dispatch = useDispatch();
const queryClient = useQueryClient();
return {
setLogin: useCallback((login) => dispatch(setLogin(login)), [dispatch]),
setLogout: useCallback(() => {
// Resets store state.
// dispatch(setStoreReset());
// Remove all cached queries.
queryClient.removeQueries();
removeAuthenticationCookies();
window.location.reload();
}, [queryClient]),
};
};
/**
* Retrieve whether the user is authenticated.
*/
export const useIsAuthenticated = () => {
return useSelector(isAuthenticated);
};
/**
* Retrieve the authentication token.
*/
export const useAuthToken = () => {
return useSelector((state) => state.authentication.token);
};
/**
* Retrieve the authentication user.
*/
export const useAuthUser = () => {
return useSelector((state) => ({}));
};
/**
* Retrieve the authenticated organization id.
*/
export const useAuthOrganizationId = () => {
return useSelector((state) => state.authentication.organizationId);
};

View File

@@ -0,0 +1,27 @@
import { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { dashboardPageTitle } from 'store/dashboard/dashboard.actions';
export const useDispatchAction = (action) => {
const dispatch = useDispatch();
return useCallback(
(payload) => {
dispatch(action(payload));
},
[dispatch, action],
);
};
export const useDashboardPageTitle = () => {
return useDispatchAction(dashboardPageTitle);
};
export const useSetAccountsTableQuery = () => {
};
export const useAccountsTableQuery = () => {
}

View File

@@ -0,0 +1,17 @@
import { useCallback } from 'react';
import { useSelector, useDispatch } from "react-redux";
import { setGlobalErrors } from 'store/globalErrors/globalErrors.actions';
export const useSetGlobalErrors = () => {
const dispatch = useDispatch();
return useCallback((errors) => {
dispatch(setGlobalErrors(errors));
}, [dispatch]);
};
export const useGlobalErrors = () => {
const globalErrors = useSelector(state => state.globalErrors.data);
return { globalErrors };
}

6
src/hooks/state/index.js Normal file
View File

@@ -0,0 +1,6 @@
export * from './dashboard';
export * from './authentication';
export * from './globalErrors';
export * from './subscriptions';
export * from './organizations';
export * from './settings';

View File

@@ -0,0 +1,11 @@
import { useCallback } from "react";
import { useDispatch } from "react-redux";
import { setOrganizations } from 'store/organizations/organizations.actions';
export const useSetOrganizations = () => {
const dispatch = useDispatch();
return useCallback((organizations) => {
dispatch(setOrganizations(organizations))
}, [dispatch]);
};

View File

@@ -0,0 +1,21 @@
import { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { setSettings } from 'store/settings/settings.actions';
export const useSetSettings = () => {
const dispatch = useDispatch();
return useCallback(
(settings) => {
dispatch(setSettings(settings));
},
[dispatch],
);
};
/**
* Retrieve the authentication token.
*/
export const useSettingsSelector = () => {
return useSelector((state) => state.settings.data);
};

View File

@@ -0,0 +1,14 @@
import { useCallback } from "react"
import { useDispatch } from "react-redux";
import { setSubscriptions } from 'store/subscription/subscription.actions';
/**
* Sets subscriptions.
*/
export const useSetSubscriptions = () => {
const dispatch = useDispatch();
return useCallback((subscriptions) => {
dispatch(setSubscriptions(subscriptions));
}, [dispatch]);
}

View File

@@ -0,0 +1,5 @@
export default function useAppRoutes() {
}

13
src/hooks/useAutofocus.js Normal file
View File

@@ -0,0 +1,13 @@
import { useRef, useEffect } from 'react';
export default function useAutofocus(focus = true) {
const ref = useRef();
useEffect(() => {
if (ref.current && focus) {
ref.current.focus();
}
}, [ref, focus]);
return ref;
}

59
src/hooks/useMedia.js Normal file
View File

@@ -0,0 +1,59 @@
import React, { useState, useRef,useCallback } from 'react';
import {
ProgressBar,
Classes,
Intent,
} from '@blueprintjs/core';
import classNames from 'classnames';
import AppToaster from 'components/AppToaster';
import { saveFilesInAsync } from 'utils';
const useMedia = ({ saveCallback, deleteCallback }) => {
const [files, setFiles] = useState([]);
const [deletedFiles, setDeletedFiles] = useState([]);
const toastKey = useRef(0);
const openProgressToast = useCallback((amount) => ({
message: (
<ProgressBar
className={classNames("toast-progress", {
[Classes.PROGRESS_NO_STRIPES]: amount >= 100,
})}
intent={amount < 100 ? Intent.PRIMARY : Intent.SUCCESS}
value={amount / 100}
/>
),
}), []);
const saveMedia = useCallback(() => {
const notUploadedFiles = files.filter((file) => file.uploaded === false);
if (notUploadedFiles.length > 0) {
toastKey.current = AppToaster.show(openProgressToast(0));
const saveAction = (formData, attachment, progressCallback) => {
return saveCallback(formData, {
onUploadProgress: (progress) => { progressCallback(progress); }
}).then((res) => {
attachment.uploaded = true;
return res;
});
};
return saveFilesInAsync(notUploadedFiles, saveAction).onProgress((progress) => {
if (progress > 0) {
AppToaster.show(openProgressToast(progress * 100), toastKey.current);
}
});
}
return Promise.resolve([]);
}, [files, openProgressToast, saveCallback]);
const deleteMedia = useCallback(() => {
return deletedFiles.length > 0
? deleteCallback(deletedFiles) : Promise.resolve();
}, [deletedFiles, deleteCallback]);
return { files, setFiles, saveMedia, deletedFiles, setDeletedFiles, deleteMedia };
}
export default useMedia;

View File

@@ -0,0 +1,31 @@
import { useQuery } from 'react-query';
import { castArray, defaultTo } from 'lodash';
import { useAuthOrganizationId } from './state';
import useApiRequest from './useRequest';
import { useRef } from 'react';
/**
* Query for tenant requests.
*/
export function useQueryTenant(query, callback, props) {
const organizationId = useAuthOrganizationId();
return useQuery([...castArray(query), organizationId], callback, props);
}
export function useRequestQuery(query, axios, props) {
const apiRequest = useApiRequest();
const states = useQuery(
query,
() => apiRequest.http({ ...axios, url: `/api/${axios.url}` }),
props,
);
// Momerize the default data.
const defaultData = useRef(props.defaultData || undefined);
return {
...states,
data: defaultTo(states.data, defaultData.current),
};
}

88
src/hooks/useRequest.js Normal file
View File

@@ -0,0 +1,88 @@
import React from 'react';
import axios from 'axios';
import {
useAuthActions,
useAuthOrganizationId,
useSetGlobalErrors,
useAuthToken,
} from './state';
import { getCookie } from '../utils';
export default function useApiRequest() {
const setGlobalErrors = useSetGlobalErrors();
const { setLogout } = useAuthActions();
const currentLocale = getCookie('locale');
// Authentication token.
const token = useAuthToken();
// Authentication organization id.
const organizationId = useAuthOrganizationId();
const http = React.useMemo(() => {
// Axios instance.
const instance = axios.create();
// Request interceptors.
instance.interceptors.request.use(
(request) => {
const locale = currentLocale;
if (token) {
request.headers.common['X-Access-Token'] = token;
}
if (organizationId) {
request.headers.common['organization-id'] = organizationId;
}
if (locale) {
request.headers.common['Accept-Language'] = locale;
}
return request;
},
(error) => {
return Promise.reject(error);
},
);
// Response interceptors.
instance.interceptors.response.use(
(response) => response,
(error) => {
const { status } = error.response;
if (status >= 500) {
setGlobalErrors({ something_wrong: true });
}
if (status === 401) {
setGlobalErrors({ session_expired: true });
setLogout();
}
return Promise.reject(error);
},
);
return instance;
}, [token, organizationId, setGlobalErrors, setLogout]);
return React.useMemo(() => ({
http,
get(resource, params) {
return http.get(`/api/${resource}`, params);
},
post(resource, params, config) {
return http.post(`/api/${resource}`, params, config);
},
update(resource, slug, params) {
return http.put(`/api/${resource}/${slug}`, params);
},
put(resource, params) {
return http.put(`/api/${resource}`, params);
},
delete(resource, params) {
return http.delete(`/api/${resource}`, params);
},
}), [http]);
}

View File

@@ -0,0 +1,38 @@
import React from 'react';
import useApiRequest from './useRequest';
export const useRequestPdf = (url) => {
const apiRequest = useApiRequest();
const [isLoading, setIsLoading] = React.useState(false);
const [isLoaded, setIsLoaded] = React.useState(false);
const [pdfUrl, setPdfUrl] = React.useState('');
const [response, setResponse] = React.useState(null);
React.useEffect(() => {
setIsLoading(true);
apiRequest
.get(url, {
headers: { accept: 'application/pdf' },
responseType: 'blob',
})
.then((response) => {
// Create a Blob from the PDF Stream.
const file = new Blob([response.data], { type: 'application/pdf' });
// Build a URL from the file
const fileURL = URL.createObjectURL(file);
setPdfUrl(fileURL);
setIsLoading(false);
setIsLoaded(true);
setResponse(response);
});
}, []);
return {
isLoading,
isLoaded,
pdfUrl,
response,
};
};