import * as React from 'react';
import fakeRestDataProvider from 'ra-data-fakerest';
import generateData from 'data-generator-retail';
import Admin from './Admin';
import {
addOfflineSupportToQueryClient,
Identifier,
Resource,
useDataProvider,
useIsOffline,
useNotify,
useRecordContext,
useRefresh,
} from 'ra-core';
import {
AppBar,
Button,
Create,
DataTable,
DateInput,
Edit,
EditButton,
Layout,
List,
NumberField,
NumberInput,
ReferenceField,
ReferenceInput,
Show,
ShowButton,
SimpleForm,
SimpleShowLayout,
TextField,
TextInput,
TitlePortal,
TopToolbar,
} from 'ra-ui-materialui';
import { onlineManager, QueryClient, useMutation } from '@tanstack/react-query';
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
export default {
title: 'react-admin/offline',
};
const baseDataProvider = fakeRestDataProvider(generateData(), true, 350);
const dataProvider = {
...baseDataProvider,
emptyStock: ({
id,
previousData,
}: {
id: Identifier;
previousData: any;
}) => {
return baseDataProvider.update('products', {
id,
data: { stock: 0 },
previousData,
});
},
};
type CustomDataProvider = typeof dataProvider;
export const FullApp = ({
failMutations = false,
}: {
failMutations?: boolean;
}) => {
const queryClient = addOfflineSupportToQueryClient({
dataProvider,
queryClient: new QueryClient({
defaultOptions: {
queries: {
gcTime: 1000 * 60 * 60 * 24, // 24 hours
},
},
}),
resources: ['products'],
});
const asyncStoragePersister = createAsyncStoragePersister({
storage: localStorage,
});
const localDataProvider = failMutations
? {
...dataProvider,
create: resource => {
return Promise.reject(
new Error(`Server error: cannot create ${resource}`)
);
},
update: resource => {
return Promise.reject(
new Error(`Server error: cannot update ${resource}`)
);
},
updateMany: resource => {
return Promise.reject(
new Error(`Server error: cannot update ${resource}`)
);
},
delete: resource => {
return Promise.reject(
new Error(`Server error: cannot delete ${resource}`)
);
},
deleteMany: resource => {
return Promise.reject(
new Error(`Server error: cannot delete ${resource}`)
);
},
emptyStock: () => {
return Promise.reject('Could not empty stock');
},
}
: dataProvider;
return (
{
// Resume mutations after initial restore from localStorage is successful
queryClient.resumePausedMutations();
}}
>
);
};
FullApp.args = {
failMutations: false,
};
FullApp.argTypes = {
failMutations: {
type: 'boolean',
},
};
const ProductList = () => (
);
const ProductEdit = () => (
}
>
);
const ProductCreate = () => (
({
id: crypto.randomUUID(),
...data,
})}
>
);
const ProductForm = () => (
);
const ProductShow = () => (
}
>
);
const EmptyStockButton = () => {
const dataProvider = useDataProvider();
const notify = useNotify();
const refresh = useRefresh();
const record = useRecordContext();
const { mutate, isPending } = useMutation({
mutationKey: ['emptyStock'],
mutationFn: (params: {
id: Identifier;
previousData: Record;
}) => dataProvider.emptyStock(params),
onSuccess: ({ data }) => {
notify(`Stock of "${data.reference}" emptied`);
refresh();
},
onError: () => {
notify('An error occured while emptying the stock');
},
});
if (!record) return null;
return (