Skip to content

Commit

Permalink
import from bucket done
Browse files Browse the repository at this point in the history
  • Loading branch information
pinocchio-life-like committed Aug 5, 2024
1 parent b655103 commit 47666fa
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 96 deletions.
65 changes: 49 additions & 16 deletions packages/app/components/item/ImportForm.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import React, { useState, FC } from 'react';
import React, { useState, useEffect, FC } from 'react';
import { View, Platform } from 'react-native';
import {
DropdownComponent,
RButton,
RText,
CascadedDropdownComponent,
} from '@packrat/ui';
import { RButton, RText, CascadedDropdownComponent } from '@packrat/ui';
import useTheme from '../../hooks/useTheme';
import * as DocumentPicker from 'expo-document-picker';
import { useImportPackItem } from 'app/hooks/packs/useImportPackItem';
Expand Down Expand Up @@ -33,15 +28,16 @@ interface SelectedType {
value: string;
}

const data = [
{ label: 'CSV', value: '.csv', key: '.csv' },
const options = [
{ label: 'Rei', value: 'rei', key: 'Rei' },
{ label: 'Sierra', value: 'sierra', key: 'Sierra' },
{ label: 'Cabelas', value: 'cabelas', key: 'Cabelas' },
{ label: 'Moosejaw', value: 'moosejaw', key: 'Moosejaw' },
{ label: 'Backcountry', value: 'backcountry', key: 'Backcountry' },
];

const csvOption = [{ label: 'CSV', value: '.csv', key: '.csv' }];

export const ImportForm: FC<ImportFormProps> = ({
packId,
ownerId,
Expand All @@ -59,19 +55,44 @@ export const ImportForm: FC<ImportFormProps> = ({
value: '.csv',
});

const [buttonText, setButtonText] = useState('Import Item');
const [isImporting, setIsImporting] = useState(false);

useEffect(() => {
let interval: NodeJS.Timeout;
if (isImporting) {
interval = setInterval(() => {
setButtonText((prev) => {
if (prev.endsWith('...')) {
return 'Importing';
} else {
return prev + '.';
}
});
}, 500);
} else {
setButtonText('Import Item');
clearInterval(interval);
}

return () => clearInterval(interval);
}, [isImporting]);

const handleSelectChange = (selectedValue: string) => {
const newValue = data.find((item) => item.value === selectedValue);
if (newValue) setSelectedType(newValue);
};

const handleItemImport = async () => {
setIsImporting(true);
try {
if (selectedType.value === '.csv') {
const res = await DocumentPicker.getDocumentAsync({
type: [selectedType.value],
});

if (res.canceled) {
setIsImporting(false);
return;
}

Expand All @@ -91,17 +112,25 @@ export const ImportForm: FC<ImportFormProps> = ({
}

if (currentpage === 'items') {
handleImportNewItems({ content: fileContent, ownerId });
handleImportNewItems({ content: fileContent, ownerId }, () => {
setIsImporting(false);
closeModalHandler();
});
} else {
importPackItem({ content: fileContent, packId, ownerId });
}
} else {
handleImportFromBucket({ directory: selectedType.value, ownerId });
handleImportFromBucket(
{ directory: selectedType.value, ownerId },
() => {
setIsImporting(false);
closeModalHandler();
},
);
}
} catch (err) {
console.error('Error importing file:', err);
} finally {
closeModalHandler();
setIsImporting(false);
}
};

Expand All @@ -118,15 +147,19 @@ export const ImportForm: FC<ImportFormProps> = ({
>
<CascadedDropdownComponent
value={selectedType}
data={data}
data={[
...(currentpage !== 'items'
? csvOption
: [...csvOption, ...options]),
]}
onValueChange={handleSelectChange}
placeholder={`Select file type: ${selectedType.label}`}
native={true}
style={{ width: '100%' }}
/>
</View>
<RButton onClick={handleItemImport}>
<RText style={{ color: currentTheme.colors.text }}>Import Item</RText>
<RButton onClick={handleItemImport} disabled={isImporting}>
<RText style={{ color: currentTheme.colors.text }}>{buttonText}</RText>
</RButton>
</View>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/app/components/item/ImportItemGlobal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const ImportItemGlobal = () => {
const ownerId = authUser?.id;

if (!authUser) {
return null; // or some fallback
return null;
}

const { setIsModalOpen } = useModal();
Expand Down
70 changes: 40 additions & 30 deletions packages/app/hooks/items/useImportFromBucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,46 +9,56 @@ interface State {

export const useImportFromBucket = () => {
const utils = queryTrpc.useContext();
const { mutate } = queryTrpc.importFromBucket.useMutation();
const { mutateAsync } = queryTrpc.importFromBucket.useMutation();
const { isConnected, addOfflineRequest } = useOfflineQueue();
const updateItems = useItemsUpdater();

const handleImportFromBucket = useCallback(
({ directory, ownerId }) => {
async ({ directory, ownerId }, onSuccess) => {
if (isConnected) {
return mutate(
{ directory, ownerId },
{
onSuccess: (data) => {
console.log('ssssssssssssssssssssssssssssssss', data.items);
// Ensure data.items exists and is an array
const newItems = Array.isArray(data.items) ? data.items : [];
try {
const data = await mutateAsync({ directory, ownerId });
const newItems = Array.isArray(data) ? data : [];
updateItems((prevState: State = {}) => {
const prevItems = Array.isArray(prevState.items)
? prevState.items
: [];
return {
...prevState,
items: [...newItems, ...prevItems],
};
});

// Update local state with the returned data
updateItems((prevState: State = {}) => {
const prevItems = Array.isArray(prevState.items)
? prevState.items
: [];
return {
...prevState,
items: [...newItems, ...prevItems],
};
});

// Invalidate the cache to reflect the latest state
utils.getItemsGlobally.invalidate();
},
onError: (error) => {
console.error('Error fetching items:', error);
},
},
);
utils.getItemsGlobally.invalidate();
utils.getItemsGlobally.refetch();
onSuccess();
} catch (error) {
console.error('Error fetching items:', error);
}
} else {
// Handle offline scenario
addOfflineRequest('importFromBucket', { directory, ownerId });

updateItems((prevState: State = {}) => {
onSuccess();
const prevItems = Array.isArray(prevState.items)
? prevState.items
: [];

return {
...prevState,
items: [
{
directory,
ownerId,
global: true,
},
...prevItems,
],
};
});
}
},
[updateItems, isConnected, mutate, utils, addOfflineRequest],
[updateItems, isConnected, mutateAsync, utils, addOfflineRequest],
);

return { handleImportFromBucket };
Expand Down
6 changes: 3 additions & 3 deletions packages/app/hooks/items/useImportItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@ export const useImportItem = () => {
const updateItems = useItemsUpdater();

const handleImportNewItems = useCallback(
(newItem) => {
(newItem, onSuccess) => {
if (isConnected) {
return mutate(newItem, {
onSuccess: () => {
// Update items only on successful mutation
updateItems((prevState: State = {}) => {
const prevItems = Array.isArray(prevState.items)
? prevState.items
: [];
return {
...prevState,
items: [newItem, ...prevItems],
items: [newItem, ...prevItems], // Use the data returned from the server
};
});
utils.getItemsGlobally.invalidate();
onSuccess();
},
onError: (error) => {
console.error('Error adding item:', error);
Expand Down
8 changes: 0 additions & 8 deletions packages/app/hooks/packs/useImportPackItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@ export const useImportPackItem = () => {
if (!newItem) {
throw new Error('Item data is not available.');
}

// Optionally: Perform optimistic update IF NEEDED

return {
// No need to store previous state if not doing optimistic updates
};
},
onSuccess: (data, newItem, context) => {
const previousPack = utils.getPackById.getData({
Expand Down Expand Up @@ -44,8 +38,6 @@ export const useImportPackItem = () => {
},
onError: (error, newItem, context) => {
console.error('Error adding item:', error);

// Optionally: Rollback optimistic update here if implemented
},
});

Expand Down
31 changes: 17 additions & 14 deletions server/src/controllers/item/importFromBucket.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { protectedProcedure } from '../../trpc';
import { addItemGlobalService } from '../../services/item/item.service';
import { bulkAddItemsGlobalService } from '../../services/item/item.service';
import * as CryptoJS from 'crypto-js';
import { parseStringPromise } from 'xml2js';
import Papa from 'papaparse';
Expand Down Expand Up @@ -248,7 +248,7 @@ export function importFromBucketRoute() {
header: true,
complete: async function (results) {
try {
const insertedItems = [];
const itemsToInsert = [];

for (const [index, item] of results.data.entries()) {
if (
Expand All @@ -258,27 +258,30 @@ export function importFromBucketRoute() {
continue;
}

const insertedItem = await addItemGlobalService(
item.name,
item.claimed_weight || 0,
item.quantity || 1,
item.claimed_weight_unit || 'g',
// item.category || 'Essentials',
'Essentials',
itemsToInsert.push({
name: item.name,
weight: item.claimed_weight || 0,
quantity: item.quantity || 1,
unit: item.claimed_weight_unit || 'g',
type: 'Essentials',
ownerId,
executionCtx,
);

insertedItems.push(insertedItem);
});
}

const insertedItems = await bulkAddItemsGlobalService(
itemsToInsert,
executionCtx,
);

return resolve(insertedItems);
} catch (error) {
console.error('Error in bulkAddItemsGlobalService:', error);

return reject(
new Error(`Failed to add items: ${error.message}`),
);
}
},
// Failed to add items: Category must be one of: Food, Water, Essentials
error: function (error) {
console.error('Error parsing CSV file:', error);
reject(error);
Expand Down
51 changes: 49 additions & 2 deletions server/src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import userRoutes from './userRoutes';
import mapPreviewRouter from './mapPreviewRouter';
import healthRoutes from './healthRoutes';
import { Hono } from 'hono';
import querystring from 'querystring';

const router = new Hono();

Expand All @@ -34,9 +35,55 @@ router.route('/favorite', favoriteRouters);
router.route('/mapPreview', mapPreviewRouter);
router.route('/health', healthRoutes);

const helloRouter = new Hono();
const testapi = new Hono();

router.route('/hello', helloRouter);
testapi.get('/', async (c) => {
const params = c.req.query();
console.log('Received data:', params);

return c.json({ message: 'Data received successfully!', data: params });
});

testapi.get('/test', async (c) => {
try {
const postData = querystring.stringify({
project: 'PackRat',
spider: 'backcountry',
});

const response = await fetch('http://localhost:6800/schedule.json', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: postData,
});

const responseData = await response.json();

if (responseData.status === 'ok') {
console.log('Scraping initiated', responseData);
return c.json({
message: 'Scraping initiated successfully!',
response: responseData,
});
} else {
console.error('Error from Scrapyd:', responseData);
return c.json({
message: 'Failed to initiate scraping',
error: responseData,
});
}
} catch (error) {
console.error('Error initiating scraping:', error);
return c.json({
message: 'Failed to initiate scraping',
error: error.toString(),
});
}
});

router.route('/testapi', testapi);

// Also listen to /api for backwards compatibility
router.route('/api/user', userRoutes);
Expand Down
Loading

0 comments on commit 47666fa

Please sign in to comment.