Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 12 additions & 20 deletions src/libs/API/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {OnyxUpdate} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import type {OnyxKey} from 'react-native-onyx';
import type {SetRequired} from 'type-fest';
import {resolveDuplicationConflictAction, resolveEnableFeatureConflicts} from '@libs/actions/RequestConflictUtils';
import type {EnablePolicyFeatureCommand, RequestMatcher} from '@libs/actions/RequestConflictUtils';
Expand All @@ -13,7 +13,7 @@ import {addMiddleware, processWithMiddleware} from '@libs/Request';
import {getAll, getLength as getPersistedRequestsLength} from '@userActions/PersistedRequests';
import CONST from '@src/CONST';
import type OnyxRequest from '@src/types/onyx/Request';
import type {PaginatedRequest, PaginationConfig, RequestConflictResolver} from '@src/types/onyx/Request';
import type {OnyxData, PaginatedRequest, PaginationConfig, RequestConflictResolver} from '@src/types/onyx/Request';
import type Response from '@src/types/onyx/Response';
import type {ApiCommand, ApiRequestCommandParameters, ApiRequestType, CommandOfType, ReadCommand, SideEffectRequestCommand, WriteCommand} from './types';
import {READ_COMMANDS} from './types';
Expand Down Expand Up @@ -51,22 +51,14 @@ addMiddleware(FraudMonitoring);

let requestIndex = 0;

type OnyxData = {
optimisticData?: OnyxUpdate[];
successData?: OnyxUpdate[];
failureData?: OnyxUpdate[];
finallyData?: OnyxUpdate[];
queueFlushedData?: OnyxUpdate[];
};

/**
* Prepare the request to be sent. Bind data together with request metadata and apply optimistic Onyx data.
*/
function prepareRequest<TCommand extends ApiCommand>(
command: TCommand,
type: ApiRequestType,
params: ApiRequestCommandParameters[TCommand],
onyxData: OnyxData = {},
onyxData: OnyxData<OnyxKey> = {},
conflictResolver: RequestConflictResolver = {},
): OnyxRequest {
Log.info('[API] Preparing request', false, {command, type});
Expand Down Expand Up @@ -155,7 +147,7 @@ function processRequest(request: OnyxRequest, type: ApiRequestType): Promise<voi
function write<TCommand extends WriteCommand>(
command: TCommand,
apiCommandParameters: ApiRequestCommandParameters[TCommand],
onyxData: OnyxData = {},
onyxData: OnyxData<OnyxKey> = {},
conflictResolver: RequestConflictResolver = {},
): Promise<void | Response> {
Log.info('[API] Called API write', false, {command, ...apiCommandParameters});
Expand All @@ -170,7 +162,7 @@ function write<TCommand extends WriteCommand>(
function writeWithNoDuplicatesConflictAction<TCommand extends WriteCommand>(
command: TCommand,
apiCommandParameters: ApiRequestCommandParameters[TCommand],
onyxData: OnyxData = {},
onyxData: OnyxData<OnyxKey> = {},
requestMatcher: RequestMatcher = (request) => request.command === command,
): Promise<void | Response> {
const conflictResolver = {
Expand All @@ -187,7 +179,7 @@ function writeWithNoDuplicatesConflictAction<TCommand extends WriteCommand>(
function writeWithNoDuplicatesEnableFeatureConflicts<TCommand extends EnablePolicyFeatureCommand>(
command: TCommand,
apiCommandParameters: ApiRequestCommandParameters[TCommand],
onyxData: OnyxData = {},
onyxData: OnyxData<OnyxKey> = {},
): Promise<void | Response> {
const conflictResolver = {
checkAndFixConflictingRequest: (persistedRequests: OnyxRequest[]) => resolveEnableFeatureConflicts(command, persistedRequests, apiCommandParameters),
Expand All @@ -207,7 +199,7 @@ function writeWithNoDuplicatesEnableFeatureConflicts<TCommand extends EnablePoli
function makeRequestWithSideEffects<TCommand extends SideEffectRequestCommand>(
command: TCommand,
apiCommandParameters: ApiRequestCommandParameters[TCommand],
onyxData: OnyxData = {},
onyxData: OnyxData<OnyxKey> = {},
): Promise<void | Response> {
Log.info('[API] Called API makeRequestWithSideEffects', false, {command, ...apiCommandParameters});
const request = prepareRequest(command, CONST.API_REQUEST_TYPE.MAKE_REQUEST_WITH_SIDE_EFFECTS, apiCommandParameters, onyxData);
Expand All @@ -231,7 +223,7 @@ function waitForWrites<TCommand extends ReadCommand>(command: TCommand) {
/**
* Requests made with this method are not be persisted to disk. If there is no network connectivity, the request is ignored and discarded.
*/
function read<TCommand extends ReadCommand>(command: TCommand, apiCommandParameters: ApiRequestCommandParameters[TCommand], onyxData: OnyxData = {}): void {
function read<TCommand extends ReadCommand>(command: TCommand, apiCommandParameters: ApiRequestCommandParameters[TCommand], onyxData: OnyxData<OnyxKey> = {}): void {
Log.info('[API] Called API.read', false, {command, ...apiCommandParameters});

// Apply optimistic updates of read requests immediately
Expand All @@ -250,29 +242,29 @@ function paginate<TRequestType extends typeof CONST.API_REQUEST_TYPE.MAKE_REQUES
type: TRequestType,
command: TCommand,
apiCommandParameters: ApiRequestCommandParameters[TCommand],
onyxData: OnyxData,
onyxData: OnyxData<OnyxKey>,
config: PaginationConfig,
): Promise<Response | void>;
function paginate<TRequestType extends typeof CONST.API_REQUEST_TYPE.READ, TCommand extends CommandOfType<TRequestType>>(
type: TRequestType,
command: TCommand,
apiCommandParameters: ApiRequestCommandParameters[TCommand],
onyxData: OnyxData,
onyxData: OnyxData<OnyxKey>,
config: PaginationConfig,
): void;
function paginate<TRequestType extends typeof CONST.API_REQUEST_TYPE.WRITE, TCommand extends CommandOfType<TRequestType>>(
type: TRequestType,
command: TCommand,
apiCommandParameters: ApiRequestCommandParameters[TCommand],
onyxData: OnyxData,
onyxData: OnyxData<OnyxKey>,
config: PaginationConfig,
conflictResolver?: RequestConflictResolver,
): void;
function paginate<TRequestType extends ApiRequestType, TCommand extends CommandOfType<TRequestType>>(
type: TRequestType,
command: TCommand,
apiCommandParameters: ApiRequestCommandParameters[TCommand],
onyxData: OnyxData,
onyxData: OnyxData<OnyxKey>,
config: PaginationConfig,
conflictResolver: RequestConflictResolver = {},
): Promise<Response | void> | void {
Expand Down
4 changes: 2 additions & 2 deletions src/libs/Network/SequentialQueue.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {OnyxUpdate} from 'react-native-onyx';
import type {OnyxKey, OnyxUpdate} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import {setIsOpenAppFailureModalOpen} from '@libs/actions/isOpenAppFailureModalOpen';
import {
Expand Down Expand Up @@ -170,7 +170,7 @@ function process(): Promise<void> {
// Duplicate records don't need to be retried as they just mean the record already exists on the server
if (error.name === CONST.ERROR.REQUEST_CANCELLED || error.message === CONST.ERROR.DUPLICATE_RECORD || shouldFailAllRequests) {
if (shouldFailAllRequests) {
const onyxUpdates = [...(requestToProcess.failureData ?? []), ...(requestToProcess.finallyData ?? [])] as OnyxUpdate[];
const onyxUpdates = [...((requestToProcess.failureData ?? []) as never), ...((requestToProcess.finallyData ?? []) as never)] as Array<OnyxUpdate<OnyxKey>>;
Onyx.update(onyxUpdates);
}
Log.info("[SequentialQueue] Removing persisted request because it failed and doesn't need to be retried.", false, {error, request: requestToProcess});
Expand Down
4 changes: 2 additions & 2 deletions src/libs/PersonalDetailsUtils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Str} from 'expensify-common';
import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx';
import type {OnyxEntry, OnyxKey, OnyxUpdate} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import type {LocaleContextProps} from '@components/LocaleContextProvider';
import CONST from '@src/CONST';
Expand All @@ -23,7 +23,7 @@
let personalDetails: Array<PersonalDetails | null> = [];
let allPersonalDetails: OnyxEntry<PersonalDetailsList> = {};
let emailToPersonalDetailsCache: Record<string, PersonalDetails> = {};
Onyx.connect({

Check warning on line 26 in src/libs/PersonalDetailsUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (val) => {
personalDetails = Object.values(val ?? {});
Expand All @@ -40,7 +40,7 @@
let hiddenTranslation = '';
let youTranslation = '';

Onyx.connect({

Check warning on line 43 in src/libs/PersonalDetailsUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.ARE_TRANSLATIONS_LOADING,
initWithStoredValues: false,
callback: (value) => {
Expand Down Expand Up @@ -215,7 +215,7 @@
newLogins: string[],
newAccountIDs: number[],
formatPhoneNumber: LocaleContextProps['formatPhoneNumber'],
): Required<Pick<OnyxData, 'optimisticData' | 'finallyData'>> {
): Required<Pick<OnyxData<OnyxKey>, 'optimisticData' | 'finallyData'>> {
const personalDetailsNew: PersonalDetailsList = {};
const personalDetailsCleanup: PersonalDetailsList = {};

Expand Down
7 changes: 6 additions & 1 deletion src/libs/PolicyDistanceRatesUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ type PolicyDistanceRateUpdateField = keyof Pick<Rate, 'name' | 'rate'> | keyof T
* @param fieldName - The field name being updated
* @returns Object containing optimisticData, successData, and failureData arrays
*/
function buildOnyxDataForPolicyDistanceRateUpdates(policyID: string, customUnit: CustomUnit, customUnitRates: Rate[], fieldName: PolicyDistanceRateUpdateField): OnyxData {
function buildOnyxDataForPolicyDistanceRateUpdates(
policyID: string,
customUnit: CustomUnit,
customUnitRates: Rate[],
fieldName: PolicyDistanceRateUpdateField,
): OnyxData<typeof ONYXKEYS.COLLECTION.POLICY> {
const currentRates = customUnit.rates;
const optimisticRates: Record<string, NullishDeep<Rate>> = {};
const successRates: Record<string, NullishDeep<Rate>> = {};
Expand Down
4 changes: 2 additions & 2 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import isNumber from 'lodash/isNumber';
import mapValues from 'lodash/mapValues';
import lodashMaxBy from 'lodash/maxBy';
import type {ColorValue} from 'react-native';
import type {NullishDeep, OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx';
import type {NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxUpdate} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import type {SvgProps} from 'react-native-svg';
import type {SetRequired, TupleToUnion, ValueOf} from 'type-fest';
Expand Down Expand Up @@ -2027,7 +2027,7 @@ function isAwaitingFirstLevelApproval(report: OnyxEntry<Report>): boolean {
* @param tagListsUpdate - Changed tag properties, if none pass empty object
*/
function pushTransactionViolationsOnyxData(
onyxData: OnyxData,
onyxData: OnyxData<OnyxKey>,
policyData: PolicyData,
policyUpdate: Partial<Policy> = {},
categoriesUpdate: Record<string, Partial<PolicyCategory>> = {},
Expand Down
4 changes: 2 additions & 2 deletions src/libs/TransactionUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import lodashDeepClone from 'lodash/cloneDeep';
import lodashHas from 'lodash/has';
import lodashSet from 'lodash/set';
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import type {OnyxCollection, OnyxEntry, OnyxKey} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import type {Coordinate} from '@components/MapView/MapViewTypes';
Expand Down Expand Up @@ -126,7 +126,7 @@
};

let deprecatedAllReports: OnyxCollection<Report> = {};
Onyx.connect({

Check warning on line 129 in src/libs/TransactionUtils/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -135,7 +135,7 @@
});

let deprecatedAllTransactionViolations: OnyxCollection<TransactionViolations> = {};
Onyx.connect({

Check warning on line 138 in src/libs/TransactionUtils/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,
waitForCollectionCallback: true,
callback: (value) => (deprecatedAllTransactionViolations = value),
Expand Down Expand Up @@ -2041,7 +2041,7 @@
*
*/
function removeTransactionFromDuplicateTransactionViolation(
onyxData: OnyxData,
onyxData: OnyxData<OnyxKey>,
transactionID: string,
transactions: OnyxCollection<Transaction>,
transactionViolations: OnyxCollection<TransactionViolations>,
Expand Down
12 changes: 10 additions & 2 deletions src/libs/actions/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,16 @@ function getOnyxDataForOpenOrReconnect(
isFullReconnect = false,
shouldKeepPublicRooms = false,
allReportsWithDraftComments?: Record<string, string | undefined>,
): OnyxData {
const result: OnyxData = {
): OnyxData<
typeof ONYXKEYS.COLLECTION.REPORT | typeof ONYXKEYS.IS_LOADING_REPORT_DATA | typeof ONYXKEYS.HAS_LOADED_APP | typeof ONYXKEYS.IS_LOADING_APP | typeof ONYXKEYS.LAST_FULL_RECONNECT_TIME
> {
const result: OnyxData<
| typeof ONYXKEYS.IS_LOADING_REPORT_DATA
| typeof ONYXKEYS.HAS_LOADED_APP
| typeof ONYXKEYS.IS_LOADING_APP
| typeof ONYXKEYS.COLLECTION.REPORT
| typeof ONYXKEYS.LAST_FULL_RECONNECT_TIME
> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down
37 changes: 20 additions & 17 deletions src/libs/actions/BankAccounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ function updateAddPersonalBankAccountDraft(bankData: Partial<PersonalBankAccount
/**
* Helper method to build the Onyx data required during setup of a Verified Business Bank Account
*/
function getVBBADataForOnyx(currentStep?: BankAccountStep, shouldShowLoading = true): OnyxData {
function getVBBADataForOnyx(currentStep?: BankAccountStep, shouldShowLoading = true): OnyxData<typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT | typeof ONYXKEYS.NVP_LAST_PAYMENT_METHOD> {
return {
optimisticData: [
{
Expand Down Expand Up @@ -215,7 +215,10 @@ function addBusinessWebsiteForDraft(websiteUrl: string) {
/**
* Get the Onyx data required to set the last used payment method to VBBA for a given policyID
*/
function getOnyxDataForConnectingVBBAAndLastPaymentMethod(policyID: string, lastPaymentMethod?: LastPaymentMethodType | string): OnyxData {
function getOnyxDataForConnectingVBBAAndLastPaymentMethod(
policyID: string,
lastPaymentMethod?: LastPaymentMethodType | string,
): OnyxData<typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT | typeof ONYXKEYS.NVP_LAST_PAYMENT_METHOD> {
const onyxData = getVBBADataForOnyx();
const lastUsedPaymentMethod = typeof lastPaymentMethod === 'string' ? lastPaymentMethod : lastPaymentMethod?.expense?.name;

Expand Down Expand Up @@ -281,7 +284,7 @@ function addPersonalBankAccount(account: PlaidBankAccount, policyID?: string, so
parameters.source = source;
}

const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.PERSONAL_BANK_ACCOUNT | typeof ONYXKEYS.USER_WALLET | typeof ONYXKEYS.NVP_LAST_PAYMENT_METHOD> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -373,7 +376,7 @@ function deletePaymentBankAccount(bankAccountID: number, lastUsedPaymentMethods?
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
};

const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.BANK_ACCOUNT_LIST | typeof ONYXKEYS.NVP_LAST_PAYMENT_METHOD> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -516,7 +519,7 @@ function validateBankAccount(bankAccountID: number, validateCode: string, policy
policyID,
};

const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -559,7 +562,7 @@ function getCorpayBankAccountFields(country: string, currency: string) {
isBusinessBankAccount: true,
};

const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.CORPAY_FIELDS> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -604,7 +607,7 @@ function createCorpayBankAccount(fields: ReimbursementAccountForm, policyID: str
policyID,
};

const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -653,7 +656,7 @@ function saveCorpayOnboardingCompanyDetails(parameters: SaveCorpayOnboardingComp
bankAccountID,
};

const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -691,7 +694,7 @@ function saveCorpayOnboardingCompanyDetails(parameters: SaveCorpayOnboardingComp
}

function saveCorpayOnboardingBeneficialOwners(parameters: SaveCorpayOnboardingBeneficialOwnerParams) {
const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -729,7 +732,7 @@ function saveCorpayOnboardingBeneficialOwners(parameters: SaveCorpayOnboardingBe
}

function saveCorpayOnboardingDirectorInformation(parameters: SaveCorpayOnboardingDirectorInformationParams) {
const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT | typeof ONYXKEYS.FORMS.ENTER_SINGER_INFO_FORM> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -792,7 +795,7 @@ function saveCorpayOnboardingDirectorInformation(parameters: SaveCorpayOnboardin
}

function askForCorpaySignerInformation(parameters: AskForCorpaySignerInformationParams) {
const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -834,7 +837,7 @@ function clearReimbursementAccount() {
}

function finishCorpayBankAccountOnboarding(parameters: FinishCorpayBankAccountOnboardingParams) {
const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -872,7 +875,7 @@ function finishCorpayBankAccountOnboarding(parameters: FinishCorpayBankAccountOn
}

function sendReminderForCorpaySignerInformation(parameters: SendReminderForCorpaySignerInformationParams) {
const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -910,7 +913,7 @@ function sendReminderForCorpaySignerInformation(parameters: SendReminderForCorpa
}

function enableGlobalReimbursementsForUSDBankAccount(parameters: EnableGlobalReimbursementsForUSDBankAccountParams) {
const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.FORMS.ENABLE_GLOBAL_REIMBURSEMENTS> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -991,7 +994,7 @@ function clearReimbursementAccountSendReminderForCorpaySignerInformation() {
* @param policyID - policy ID
*/
function openReimbursementAccountPage(stepToOpen: ReimbursementAccountStep, subStep: ReimbursementAccountSubStep, localCurrentStep: ReimbursementAccountStep, policyID: string) {
const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -1238,7 +1241,7 @@ function createCorpayBankAccountForWalletFlow(data: InternationalBankAccountForm
inputs: JSON.stringify(inputData),
};

const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down Expand Up @@ -1296,7 +1299,7 @@ function shareBankAccount(bankAccountID: number, emailList: string[]) {
emailList,
};

const onyxData: OnyxData = {
const onyxData: OnyxData<typeof ONYXKEYS.SHARE_BANK_ACCOUNT> = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down
Loading
Loading