diff --git a/client/components/ScoreContainer.tsx b/client/components/ScoreContainer.tsx index f430f4f9e..be915d58f 100644 --- a/client/components/ScoreContainer.tsx +++ b/client/components/ScoreContainer.tsx @@ -212,7 +212,7 @@ export default function ScoreContainer({ type, data, isOwner }) { {isAlreadyScored && ( <> - {/* */} + )} diff --git a/client/components/item/AddItem.tsx b/client/components/item/AddItem.tsx index b285253cf..7fa8149fe 100644 --- a/client/components/item/AddItem.tsx +++ b/client/components/item/AddItem.tsx @@ -1,15 +1,8 @@ import { useEffect, useState } from 'react'; import { View } from 'react-native'; import { useDispatch, useSelector } from 'react-redux'; -import { - addPackItem, - editPackItem, - editItemsGlobalAsDuplicate, -} from '../../store/packsStore'; import { ItemForm } from './ItemForm'; // assuming you moved the form related code to a separate component -import { ItemCategoryEnum } from '../../constants/itemCategory'; import { useAddPackItem } from '~/hooks/packs/useAddPackItem'; -import { add } from 'date-fns'; import { useEditPackItem } from '~/hooks/packs/useEditPackItem'; export const AddItem = ({ @@ -24,8 +17,6 @@ export const AddItem = ({ closeModalHandler, setIsAddItemModalOpen = () => {}, }) => { - const dispatch = useDispatch(); - const isLoading = useSelector((state) => state.packs.isLoading); // Moved the state up to the parent component const [name, setName] = useState(initialData?.name || ''); @@ -41,11 +32,14 @@ export const AddItem = ({ const { // mutation: addPackItemMutation + isLoading, + isError, addPackItem, } = useAddPackItem(); const { // mutation: addPackItemMutation + editPackItem, } = useEditPackItem(); @@ -62,7 +56,6 @@ export const AddItem = ({ * * @return {type} description of return value */ - console.log(categoryType); const handleSubmit = () => { const PackId = packId || initialData._id; @@ -74,7 +67,7 @@ export const AddItem = ({ quantity, unit, type: categoryType, - _id: initialData._id, + // _id: initialData._id, }); closeModalHandler(); } else { @@ -84,8 +77,8 @@ export const AddItem = ({ quantity, unit, type: categoryType, - _id, - packId, + // _id, + // packId, }); setPage(1); closeModalHandler(); @@ -97,8 +90,7 @@ export const AddItem = ({ quantity, type: categoryType, unit, - _id, - packId, + packId }); } }; diff --git a/client/components/item/searchItem.tsx b/client/components/item/searchItem.tsx index 87dd94213..0fd3648c8 100644 --- a/client/components/item/searchItem.tsx +++ b/client/components/item/searchItem.tsx @@ -17,8 +17,7 @@ export const SearchItem: React.FC = ({ onSelect, placeholder }) => { const [selectedSearch, setSelectedSearch] = useState(''); const searchResults = - useSelector((state: any) => state.search.searchResults.items) || []; - + useSelector((state: any) => state.search.searchResults) || []; const user = useSelector((state: any) => state.auth.user); const [showSearchResults, setShowSearchResults] = useState(false); @@ -33,7 +32,7 @@ export const SearchItem: React.FC = ({ onSelect, placeholder }) => { const ownerId = user._id; // @ts-expect-error const packId = window.location.pathname.substring('/path/'.length); - const selectedItem = item._id; + const selectedItem = item?._id; const data = { ownerId, packId, @@ -87,6 +86,8 @@ export const SearchItem: React.FC = ({ onSelect, placeholder }) => { } disabled={!showSearchResults} /> + + {showSearchResults && searchResults?.length > 0 && ( void; + onCancel?: () => void; + buttonColor?: string; + type?: string; + size?: string; + footerButtons?: any[]; + isActive: boolean; + onTrigger: (value: boolean) => void; + buttonText?: string; + triggerComponent?: React.ReactNode; +}; export const CustomModal = ({ id, title, @@ -20,7 +36,7 @@ export const CustomModal = ({ buttonText, triggerComponent = null, ...rest -}) => { +}:PropTypes) => { /** * * Closes the modal either by calling the onCancel function or by triggering the onTrigger function with a value of false. diff --git a/client/components/pack/AddPack.tsx b/client/components/pack/AddPack.tsx index 0881cfad1..a1d5f6cfb 100644 --- a/client/components/pack/AddPack.tsx +++ b/client/components/pack/AddPack.tsx @@ -9,42 +9,44 @@ import useTheme from '../../hooks/useTheme'; import useCustomStyles from '~/hooks/useCustomStyles'; import { useAddNewPack } from '~/hooks/packs'; import { useRouter } from 'expo-router'; +import { Box, Button, CheckIcon, Input, Select, Text } from 'native-base'; +import { packSelectOptions } from '~/constants/options'; + export const AddPack = ({ isCreatingTrip = false }) => { + //Hooks const { enableDarkMode, enableLightMode, isDark, isLight, currentTheme } = useTheme(); const styles = useCustomStyles(loadStyles); - - const dispatch = useDispatch(); const router = useRouter(); - const [name, setName] = useState(''); - const [isPublic, setIsPublic] = useState(false); + const { + addNewPack, + isSuccess, + isError, + response, + error, + isLoading, + name, + setIsPublic, + setName, + } = useAddNewPack(); - // const { addPack } = useAddPack(); - // const { user } = useAuth(); - const user = useSelector((state) => state.auth.user); - const isLoading = useSelector((state) => state.packs.isLoading); - const { addNewPack, isSuccess, isError, response } = useAddNewPack(); + //routing if (isSuccess && !isCreatingTrip && response) { router.push(`/pack/${response.createdPack._id}`); } /** * Handles the addition of a pack. - * - * @param {string} name - The name of the pack. - * @param {string} owner_id - The ID of the pack's owner. * @return {void} */ const handleAddPack = () => { - addNewPack({ name, owner_id: user?._id, is_public: isPublic }); - setName(''); + addNewPack(); }; - const data = ['Yes', 'For me only']; - const handleonValueChange = (itemValue) => { - setIsPublic(itemValue == 'Yes'); + if (itemValue === 'Yes') setIsPublic(true); + else setIsPublic(false); }; return ( @@ -60,9 +62,9 @@ export const AddPack = ({ isCreatingTrip = false }) => { /> Is Public: { width: '100%', paddingHorizontal: 18, gap: 20, + marginTop: 20, }, desktopStyle: { flexDirection: 'row', diff --git a/client/components/pack/PackContainer.tsx b/client/components/pack/PackContainer.tsx index 705241d75..29a4e2473 100644 --- a/client/components/pack/PackContainer.tsx +++ b/client/components/pack/PackContainer.tsx @@ -23,9 +23,6 @@ export default function PackContainer({ isCreatingTrip = false }) { const [isAddItemModalOpen, setIsAddItemModalOpen] = useState(false); const user = useSelector((state) => state.auth.user); - // const packs = useSelector(selectAllPacks); - - const newTrip = useSelector((state) => state.trips.newTrip); const [currentPackId, setCurrentPackId] = useState(null); const [refetch, setRefetch] = useState(false); diff --git a/client/components/pack/PackDetails.tsx b/client/components/pack/PackDetails.tsx index 24adfbf5b..6a95e68d0 100644 --- a/client/components/pack/PackDetails.tsx +++ b/client/components/pack/PackDetails.tsx @@ -20,12 +20,8 @@ import { useUserPacks } from '~/hooks/packs/useUserPacks'; import { useFetchSinglePack } from '../../hooks/packs'; export function PackDetails() { - const searchParams = new URLSearchParams(window.location.search); - + const searchParams = new URLSearchParams(this.location.search); const canCopy = searchParams.get('copy'); - - const dispatch = useDispatch(); - const { packId } = useSearchParams(); const link = `${CLIENT_URL}/packs/${packId}`; const updated = useSelector((state) => state.packs.update); diff --git a/client/constants/options.ts b/client/constants/options.ts new file mode 100644 index 000000000..4f10e990d --- /dev/null +++ b/client/constants/options.ts @@ -0,0 +1,4 @@ +export const packSelectOptions = [ + { value: 'Yes', label: 'Yes' }, + { value: 'For me only', label: 'For me only' }, + ]; diff --git a/client/hooks/packs/useAddNewPack.ts b/client/hooks/packs/useAddNewPack.ts index 1312b797c..93203c2d9 100644 --- a/client/hooks/packs/useAddNewPack.ts +++ b/client/hooks/packs/useAddNewPack.ts @@ -1,21 +1,36 @@ +import { useState } from 'react'; import { queryTrpc } from '../../trpc'; +import { useSelector } from 'react-redux'; export const useAddNewPack = () => { + const user = useSelector((state) => state.auth.user); + const [name, setName] = useState(''); + const [isPublic, setIsPublic] = useState(false); const utils = queryTrpc.useContext(); + // Use mutation for adding a pack + + const addNewPack = () => { + mutation.mutate({ + name: name, + is_public: isPublic, + owner_id: user?._id, + }); + } + const mutation = queryTrpc.addPack.useMutation({ - onMutate: async (newPack) => { + onMutate: async (packData) => { utils.getPacks.cancel({ - ownerId: newPack?.owner_id, + ownerId: packData?.owner_id, queryBy: '', }); // Step 1: Define optimistic update const optimisticUpdate = { - ...newPack, + ...packData, id: Date.now(), }; const oldQueryData = utils.getPacks.getData({ - ownerId: newPack?.owner_id, + ownerId: packData?.owner_id, queryBy: '', }); @@ -28,17 +43,18 @@ export const useAddNewPack = () => { }; utils.getPacks.setData( { - ownerId: newPack.owner_id, + ownerId: packData.owner_id, queryBy: '', }, (oldQueryData) => newQueryData, ); + setName(''); + setIsPublic(false); return { oldQueryData, }; }, onError: (_error, _pack, context) => { - console.log('error'); console.log(context.oldQueryData); utils.getPacks.setData( { @@ -54,11 +70,15 @@ export const useAddNewPack = () => { }); return { mutation, - addNewPack: mutation.mutate, + addNewPack, isLoading: mutation.isLoading, isError: mutation.isError, isSuccess: mutation.isSuccess, error: mutation.error, response: mutation.data, + name, + isPublic, + setIsPublic, + setName }; }; diff --git a/client/hooks/search/useSearchInput.ts b/client/hooks/search/useSearchInput.ts index 79b13a85e..0189a3ac3 100644 --- a/client/hooks/search/useSearchInput.ts +++ b/client/hooks/search/useSearchInput.ts @@ -6,13 +6,14 @@ import { } from '../../store/searchStore'; import { setLatLng } from '../../store/weatherStore'; import { usePhotonDetail } from '~/hooks/photonDetail'; +import { RootState } from 'store/store'; const useSearchInput = (onSelect) => { const [searchString, setSearchString] = useState(''); const [showSearchResults, setShowSearchResults] = useState(false); const [isLoadingMobile, setIsLoadingMobile] = useState(false); const selectedSearchResult = - useSelector((state) => state.search.selectedSearchResult) || {}; + useSelector((state:RootState) => state.search.selectedSearchResult) || {}; const { refetch, data } = usePhotonDetail(searchString, showSearchResults); diff --git a/client/store/packsStore.ts b/client/store/packsStore.ts index f6e891fbf..9d061db26 100644 --- a/client/store/packsStore.ts +++ b/client/store/packsStore.ts @@ -83,6 +83,8 @@ export const duplicatePackItem = createAsyncThunk( }, ); + + export const scorePack = createAsyncThunk('packs/scorePack', async (packId) => { // const response = await axios.put(`${api}/pack/score/${packId}`); // return response.data; @@ -315,8 +317,8 @@ const packsSlice = createSlice({ }) .addCase(scorePack.fulfilled, (state, action) => { packsAdapter.updateOne(state, { - id: action.payload.updatedPack._id, - changes: action.payload.updatedPack, + id: action.payload._id, + changes: action.payload, }); state.isLoading = false; state.error = null; diff --git a/client/store/searchStore.ts b/client/store/searchStore.ts index 3fcfb8bc1..f9dee1ca7 100644 --- a/client/store/searchStore.ts +++ b/client/store/searchStore.ts @@ -27,11 +27,10 @@ export const fetchItemsSearchResults = createAsyncThunk( 'search/fetchItemsSearchResults', async (searchString) => { const url = api + `/item/global?search=${encodeURIComponent(searchString)}`; - try { // const response = await axios.get(url); // return response.data; - return await trpc.getItemsGlobally.query({ searchString }); + return await trpc.getItemsGlobally.query({limit:5, page:0, searchString }); } catch (error) { console.error('error:' + error); } diff --git a/client/store/store.ts b/client/store/store.ts index fd74bf07f..b07c2b66d 100644 --- a/client/store/store.ts +++ b/client/store/store.ts @@ -34,7 +34,7 @@ import progressReducer from './progressStore'; import { type Reducer } from 'react'; // combine reducers -const rootReducer: Reducer = combineReducers({ +const rootReducer = combineReducers({ auth: authReducer, dropdown: dropdownReducer, search: searchReducer, @@ -57,29 +57,8 @@ const rootReducer: Reducer = combineReducers({ // trails : trailsReducer trails: trailsReducer2, // TODO: remove. This was super hacky fix for trailsReducer not working. No idea why it's not working. }); +export type RootState = ReturnType -export interface RootState { - auth: typeof authReducer; - dropdown: typeof dropdownReducer; - search: typeof searchReducer; - weather: typeof weatherReducer; - parks: typeof parksReducer; - items: typeof itemsReducer; - packs: typeof packsReducer; - trips: typeof tripsReducer; - favorites: typeof favoritesReducer; - singlePack: typeof singlePackReducer; - singleTrip: typeof singleTripReducer; - feed: typeof feedReducer; - gpx: typeof gpxReducer; - destination: typeof destinationReducer; - chat: typeof chatReducer; - globalItems: typeof globalItems; - userStore: typeof userStore; - offlineQueue: typeof offlineQueue; - progress: typeof progressReducer; - trails: typeof trailsReducer2; -} // configure persist store and whitelist reducers const persistConfig: PersistConfig = { diff --git a/server/src/controllers/item/getItemsGlobally.ts b/server/src/controllers/item/getItemsGlobally.ts index ca1ad72ad..703e9353e 100644 --- a/server/src/controllers/item/getItemsGlobally.ts +++ b/server/src/controllers/item/getItemsGlobally.ts @@ -15,6 +15,7 @@ export const getItemsGlobally = async (req, res, next) => { const result = await getItemsGloballyService( req.query.limit, req.query.page, + req.query.searchString, ); res.locals.data = result; responseHandler(res); @@ -26,8 +27,12 @@ export const getItemsGlobally = async (req, res, next) => { export function getItemsGloballyRoute() { console.log('Route'); return publicProcedure - .input(z.object({ limit: z.number(), page: z.number() })) + .input(z.object({ + limit: z.number(), + page: z.number(), + searchString: z.string().optional(), + })) .query(async (opts) => { - return await getItemsGloballyService(opts.input.limit, opts.input.page); + return await getItemsGloballyService(opts.input.limit, opts.input.page, opts.input.searchString); }); } diff --git a/server/src/services/item/addItemService.ts b/server/src/services/item/addItemService.ts index 93689e219..b36281b4b 100644 --- a/server/src/services/item/addItemService.ts +++ b/server/src/services/item/addItemService.ts @@ -24,70 +24,21 @@ export const addItemService = async ( type, ownerId, ) => { - let category = null; let newItem = null; - - switch (type) { - case ItemCategoryEnum.FOOD: { - category = await ItemCategoryModel.findOne({ - name: ItemCategoryEnum.FOOD, - }); - - newItem = await Item.create({ - name, - weight, - quantity, - unit, - packs: [packId], - category: category._id, - }); - - break; - } - case ItemCategoryEnum.WATER: { - category = await ItemCategoryModel.findOne({ - name: ItemCategoryEnum.WATER, - }); - - const existingWaterItem = await Item.findOne({ - category: category._id, - packs: packId, - }); - - if (existingWaterItem) { - existingWaterItem.weight += Number(weight); // Ensure weight is treated as a number - await existingWaterItem.save(); - newItem = existingWaterItem; - } else { - newItem = await Item.create({ - name, - weight, - quantity: 1, - unit, - packs: [packId], - category: category._id, - }); - } - - break; - } - default: { - category = await ItemCategoryModel.findOne({ - name: ItemCategoryEnum.ESSENTIALS, - }); - - newItem = await Item.create({ - name, - weight, - quantity, - unit, - packs: [packId], - category: category._id, - }); - - break; - } - } + const category = await ItemCategoryModel.findOne({ + name: ItemCategoryEnum[type], + }); + + newItem = await Item.create({ + name, + weight, + quantity, + unit, + packs: [packId], + category: category? category._id : null, + }); + + await Pack.updateOne({ _id: packId }, { $addToSet: { items: newItem._id } }); const updatedItem = await Item.findByIdAndUpdate( diff --git a/server/src/services/item/getItemsGloballyService.ts b/server/src/services/item/getItemsGloballyService.ts index 181a266c1..3df64d62a 100644 --- a/server/src/services/item/getItemsGloballyService.ts +++ b/server/src/services/item/getItemsGloballyService.ts @@ -6,8 +6,8 @@ import Item from '../../models/itemModel'; * @param {Object} req - The request object. * @return {Object} An object containing items, page, and totalPages. */ -export const getItemsGloballyService = async (reqlimit: any, reqpage: any) => { - const totalItems = await Item.countDocuments({ global: true }); +export const getItemsGloballyService = async (reqlimit: any, reqpage: any, searchString:string) => { + const totalItems = await Item.countDocuments({ global: true, name: { $regex: searchString, $options: 'i' } }); const limit = Number(reqlimit) || totalItems; const totalPages = Math.ceil(totalItems / limit); const page = Number(reqpage) || 1;