ソースを参照

Finished feature 564

feature/587
Djordje Mitrovic 3年前
コミット
da2d36127f

+ 9
- 8
src/components/Header/Header.js ファイルの表示

import CreateOffer from "../Cards/CreateOfferCard/CreateOffer"; import CreateOffer from "../Cards/CreateOfferCard/CreateOffer";
import { Drawer as HeaderDrawer } from "./Drawer/Drawer"; import { Drawer as HeaderDrawer } from "./Drawer/Drawer";
import useSearch from "../../hooks/useOffers/useSearch"; import useSearch from "../../hooks/useOffers/useSearch";
import { routeMatches } from "../../util/helpers/routeHelpers";
// import useQueryString from "../../hooks/useOffers/useQueryString"; // import useQueryString from "../../hooks/useOffers/useQueryString";


const Header = () => { const Header = () => {
useEffect(() => { useEffect(() => {
let shouldShowHeader = true; let shouldShowHeader = true;
if ( if (
location.pathname === LOGIN_PAGE ||
location.pathname === REGISTER_PAGE ||
location.pathname === REGISTER_SUCCESSFUL_PAGE ||
location.pathname === FORGOT_PASSWORD_PAGE ||
location.pathname === FORGOT_PASSWORD_MAIL_SENT ||
location.pathname === RESET_PASSWORD_PAGE
routeMatches(LOGIN_PAGE) ||
routeMatches(REGISTER_PAGE) ||
routeMatches(REGISTER_SUCCESSFUL_PAGE) ||
routeMatches(FORGOT_PASSWORD_PAGE) ||
routeMatches(FORGOT_PASSWORD_MAIL_SENT) ||
routeMatches(RESET_PASSWORD_PAGE)
) { ) {
shouldShowHeader = false; shouldShowHeader = false;
} }
}; };
const handleSearch = (value) => { const handleSearch = (value) => {
if ( if (
history.location.pathname !== HOME_PAGE &&
history.location.pathname !== BASE_PAGE
!routeMatches(HOME_PAGE) &&
!routeMatches(BASE_PAGE)
) { ) {
const newQueryString = new URLSearchParams({ search: value }); const newQueryString = new URLSearchParams({ search: value });
history.push({ history.push({

+ 7
- 5
src/hooks/useOffers/useOffers.js ファイルの表示

import { fetchLocations } from "../../store/actions/locations/locationsActions"; import { fetchLocations } from "../../store/actions/locations/locationsActions";
import { import {
selectOffers, selectOffers,
selectPinnedOffers,
selectTotalOffers, selectTotalOffers,
} from "../../store/selectors/offersSelectors"; } from "../../store/selectors/offersSelectors";
import useFilters from "./useFilters"; import useFilters from "./useFilters";
const dispatch = useDispatch(); const dispatch = useDispatch();
const filters = useFilters(); const filters = useFilters();
const queryStringHook = useQueryString(); const queryStringHook = useQueryString();
const pinnedOffers = useSelector(selectPinnedOffers);
const offers = useSelector(selectOffers); const offers = useSelector(selectOffers);
const totalOffers = useSelector(selectTotalOffers); const totalOffers = useSelector(selectTotalOffers);
const history = useHistory(); const history = useHistory();
if (history.location.state?.logo) { if (history.location.state?.logo) {
clear(); clear();
} }
}, [history.location])
}, [history.location]);


// On every change of query string, new header string should be created // On every change of query string, new header string should be created
// Header string is shown on Home page above offers // Header string is shown on Home page above offers
}, [queryStringHook.isInitiallyLoaded]); }, [queryStringHook.isInitiallyLoaded]);


const allOffersToShow = useMemo(() => { const allOffersToShow = useMemo(() => {
return offers;
}, [offers]);
return [...pinnedOffers, ...offers];
}, [offers, pinnedOffers]);


useEffect(() => { useEffect(() => {
if (filtersCleared) { if (filtersCleared) {
setFiltersCleared(false); setFiltersCleared(false);
apply(); apply();
} }
}, [filtersCleared])
}, [filtersCleared]);


const apply = () => { const apply = () => {
filters.apply(); filters.apply();
const clearFiltersAndApply = () => { const clearFiltersAndApply = () => {
clear(); clear();
setFiltersCleared(true); setFiltersCleared(true);
}
};


// Those hooks are below becouse function apply cannot be put on props before initialization // Those hooks are below becouse function apply cannot be put on props before initialization
const sorting = useSorting(apply); const sorting = useSorting(apply);

+ 1
- 0
src/request/apiEndpoints.js ファイルの表示

offers: { offers: {
getOneOffer: "offers", getOneOffer: "offers",
getOffers: "offers", getOffers: "offers",
getFeaturedOffers: "offers/featured",
addOffer: "offers", addOffer: "offers",
categories: "categories", categories: "categories",
locations: "locations", locations: "locations",

+ 4
- 0
src/request/offersRequest.js ファイルの表示

if (payload) return getRequest(apiEndpoints.offers.getOffers + payload); if (payload) return getRequest(apiEndpoints.offers.getOffers + payload);
return getRequest(apiEndpoints.offers.getOffers); return getRequest(apiEndpoints.offers.getOffers);
}; };
export const attemptFetchFeaturedOffers = (payload) => {
if (payload) return getRequest(apiEndpoints.offers.getFeaturedOffers + payload);
return getRequest(apiEndpoints.offers.getOffers);
}
export const attemptFetchOneOffer = (payload) => { export const attemptFetchOneOffer = (payload) => {
const url = `${apiEndpoints.offers.getOneOffer}/${payload}`; const url = `${apiEndpoints.offers.getOneOffer}/${payload}`;
return getRequest(url); return getRequest(url);

+ 16
- 0
src/store/actions/offers/offersActionConstants.js ファイルの表示

export const OFFERS_ERROR = createErrorType(OFFERS_SCOPE); export const OFFERS_ERROR = createErrorType(OFFERS_SCOPE);
export const OFFERS_CLEAR = createClearType(OFFERS_SCOPE); export const OFFERS_CLEAR = createClearType(OFFERS_SCOPE);


export const OFFERS_FEATURED_SCOPE = "OFFERS_FEATURED_SCOPE";
export const OFFERS_FEATURED_FETCH = createFetchType(OFFERS_FEATURED_SCOPE);
export const OFFERS_FEATURED_SUCCESS = createSuccessType(OFFERS_FEATURED_SCOPE);
export const OFFERS_FEATURED_ERROR = createErrorType(OFFERS_FEATURED_SCOPE);
export const OFFERS_FEATURED_CLEAR = createClearType(OFFERS_FEATURED_SCOPE);

export const OFFERS_ALL_SCOPE = "OFFERS_ALL_SCOPE";
export const OFFERS_ALL_FETCH = createFetchType(OFFERS_ALL_SCOPE);
export const OFFERS_ALL_SUCCESS = createSuccessType(OFFERS_ALL_SCOPE);
export const OFFERS_ALL_ERROR = createErrorType(OFFERS_ALL_SCOPE);

export const OFFERS_MORE_SCOPE = "OFFERS_MORE_SCOPE"; export const OFFERS_MORE_SCOPE = "OFFERS_MORE_SCOPE";
export const OFFERS_FETCH_MORE = createFetchType(OFFERS_MORE_SCOPE); export const OFFERS_FETCH_MORE = createFetchType(OFFERS_MORE_SCOPE);
export const OFFERS_FETCH_MORE_SUCCESS = createSuccessType(OFFERS_MORE_SCOPE) export const OFFERS_FETCH_MORE_SUCCESS = createSuccessType(OFFERS_MORE_SCOPE)
export const OFFERS_PINNED_SET = createSetType("OFFERS_PINNED_SET"); export const OFFERS_PINNED_SET = createSetType("OFFERS_PINNED_SET");
export const OFFERS_PINNED_ADD = createSetType("OFFERS_PINNED_ADD"); export const OFFERS_PINNED_ADD = createSetType("OFFERS_PINNED_ADD");
export const OFFERS_SET = createSetType("OFFERS_SET"); export const OFFERS_SET = createSetType("OFFERS_SET");
export const OFFERS_FEATURED_SET = createSetType("OFFERS_FEATURED_SET");
export const OFFER_SET = createSetType("OFFER_SET"); export const OFFER_SET = createSetType("OFFER_SET");
export const OFFERS_ADD = createSetType("OFFERS_ADD"); export const OFFERS_ADD = createSetType("OFFERS_ADD");
export const OFFERS_NO_MORE = createSetType("OFFERS_NO_MORE"); export const OFFERS_NO_MORE = createSetType("OFFERS_NO_MORE");
export const OFFERS_SET_TOTAL = createSetType("OFFERS_SET_TOTAL"); export const OFFERS_SET_TOTAL = createSetType("OFFERS_SET_TOTAL");
export const OFFERS_PROFILE_SET = createSetType("OFFERS_PROFILE_SET"); export const OFFERS_PROFILE_SET = createSetType("OFFERS_PROFILE_SET");
export const OFFERS_MINE_SET = createSetType("OFFERS_MY_ADD"); export const OFFERS_MINE_SET = createSetType("OFFERS_MY_ADD");
export const OFFER_INDEX_SET = createSetType("OFFER_INDEX_SET");
export const OFFER_INDEX_CLEAR = createClearType("OFFER_INDEX_CLEAR");
export const OFFER_PAGE_SET = createSetType("OFFER_PAGE_SET");
export const OFFER_FEATURED_PAGE_SET = createSetType("OFFER_FEATURED_PAGE_SET");


export const OFFER_ADD_SCOPE = "OFFER_ADD_SCOPE"; export const OFFER_ADD_SCOPE = "OFFER_ADD_SCOPE";
export const OFFER_ADD = createFetchType(OFFER_ADD_SCOPE); export const OFFER_ADD = createFetchType(OFFER_ADD_SCOPE);

+ 50
- 0
src/store/actions/offers/offersActions.js ファイルの表示

OFFERS_ADD, OFFERS_ADD,
OFFERS_CLEAR, OFFERS_CLEAR,
OFFERS_ERROR, OFFERS_ERROR,
OFFERS_FEATURED_CLEAR,
OFFERS_FEATURED_ERROR,
OFFERS_FEATURED_FETCH,
OFFERS_FEATURED_SET,
OFFERS_FEATURED_SUCCESS,
OFFERS_FETCH, OFFERS_FETCH,
OFFERS_FETCH_MORE, OFFERS_FETCH_MORE,
OFFERS_FETCH_MORE_ERROR, OFFERS_FETCH_MORE_ERROR,
OFFER_EDIT, OFFER_EDIT,
OFFER_EDIT_ERROR, OFFER_EDIT_ERROR,
OFFER_EDIT_SUCCESS, OFFER_EDIT_SUCCESS,
OFFER_FEATURED_PAGE_SET,
OFFER_PAGE_SET,
OFFER_REMOVE, OFFER_REMOVE,
OFFER_REMOVE_ERROR, OFFER_REMOVE_ERROR,
OFFER_REMOVE_SUCCESS, OFFER_REMOVE_SUCCESS,
type: OFFERS_CLEAR, type: OFFERS_CLEAR,
}); });


// Fetch offers
export const fetchAllOffers = (payload) => ({
type: OFFERS_FETCH,
payload,
});
export const fetchAllOffersSuccess = (payload) => ({
type: OFFERS_SUCCESS,
payload,
});
export const fetchAllOffersError = (payload) => ({
type: OFFERS_ERROR,
payload,
});

// Fetch featured offers
export const fetchFeaturedOffers = (payload) => ({
type: OFFERS_FEATURED_FETCH,
payload,
});
export const fetchFeaturedOffersSuccess = (payload) => ({
type: OFFERS_FEATURED_SUCCESS,
payload,
});
export const fetchFeaturedOffersError = (payload) => ({
type: OFFERS_FEATURED_ERROR,
payload,
});
export const clearFeaturedOffers = () => ({
type: OFFERS_FEATURED_CLEAR,
});

// Fetch more offers // Fetch more offers
export const fetchMoreOffers = (payload) => ({ export const fetchMoreOffers = (payload) => ({
type: OFFERS_FETCH_MORE, type: OFFERS_FETCH_MORE,
type: OFFER_SET, type: OFFER_SET,
payload, payload,
}); });
export const setFeaturedOffers = (payload) => ({
type: OFFERS_FEATURED_SET,
payload
})
export const setOfferPage = (payload) => ({
type: OFFER_PAGE_SET,
payload
})
export const setFeaturedOfferPage = (payload) => ({
type: OFFER_FEATURED_PAGE_SET,
payload
})

+ 79
- 27
src/store/reducers/offers/offersReducer.js ファイルの表示

ONE_OFFER_SUCCESS, ONE_OFFER_SUCCESS,
OFFERS_SET_TOTAL, OFFERS_SET_TOTAL,
OFFERS_PROFILE_SET, OFFERS_PROFILE_SET,
OFFERS_FEATURED_CLEAR,
OFFERS_FEATURED_SET,
OFFER_INDEX_SET,
OFFER_INDEX_CLEAR,
OFFER_PAGE_SET,
OFFER_FEATURED_PAGE_SET,
} from "../../actions/offers/offersActionConstants"; } from "../../actions/offers/offersActionConstants";
import createReducer from "../../utils/createReducer"; import createReducer from "../../utils/createReducer";


total: 0, total: 0,
error: "", error: "",
newOffer: "", newOffer: "",
selectedOffer:"",
selectedOffer: "",
noMoreOffers: false, noMoreOffers: false,
offerIndex: null,
offerPage: null,
featuredOfferPage: null,
}; };


export default createReducer( export default createReducer(
[OFFERS_SET_TOTAL]: setTotalOffers, [OFFERS_SET_TOTAL]: setTotalOffers,
[OFFERS_MINE_SET]: setMineOffers, [OFFERS_MINE_SET]: setMineOffers,
[OFFERS_PROFILE_SET]: setProfileOffers, [OFFERS_PROFILE_SET]: setProfileOffers,
[OFFERS_FEATURED_CLEAR]: clearFeaturedOffers,
[OFFERS_FEATURED_SET]: setFeaturedOffers,
[OFFER_INDEX_SET]: setOfferIndex,
[OFFER_INDEX_CLEAR]: clearOfferIndex,
[OFFER_PAGE_SET]: setOfferPage,
[OFFER_FEATURED_PAGE_SET]: setFeaturedOfferPage,
}, },
initialState initialState
); );
return { ...state, error: action.payload }; return { ...state, error: action.payload };
} }


function clearOffers() {
return initialState;
function clearOffers(state) {
return { ...state, offers: [] };
} }
function setOffers(state, action) { function setOffers(state, action) {
return { return {
function addOffers(state, action) { function addOffers(state, action) {
return { return {
...state, ...state,
offers: [...state.offers, ...action.payload]
}
offers: [...state.offers, ...action.payload],
};
} }
function setPinnedOffers(state, action) { function setPinnedOffers(state, action) {
return { return {
...state, ...state,
pinnedOffers: [...action.payload]
}
pinnedOffers: [...action.payload],
};
} }
function addOffer(state, action) { function addOffer(state, action) {
return { return {
...state, ...state,
offer: action.payload
}
offer: action.payload,
};
} }


function fetchOneOffer(state,action) {
function fetchOneOffer(state, action) {
return { return {
...state, ...state,
selectedOffer: action.payload
}
selectedOffer: action.payload,
};
} }
function fetchOneOfferSuccess( state, action) {
function fetchOneOfferSuccess(state, action) {
return { return {
...state, ...state,
selectedOffer: action.payload
}
selectedOffer: action.payload,
};
} }
function fetchOneOfferError (state, action) {
function fetchOneOfferError(state, action) {
return { return {
...state, ...state,
error: action.payload
}
error: action.payload,
};
} }
function addPinnedOffers(state, action) { function addPinnedOffers(state, action) {
return { return {
...state, ...state,
pinnedOffers: [...state.pinnedOffers, ...action.payload]
}
pinnedOffers: [...state.pinnedOffers, ...action.payload],
};
} }
function setNoMoreOffersStatus(state, action) { function setNoMoreOffersStatus(state, action) {
return { return {
...state, ...state,
noMoreOffers: action.payload
}
noMoreOffers: action.payload,
};
} }
function setTotalOffers(state, action) { function setTotalOffers(state, action) {
return { return {
...state, ...state,
total: action.payload
}
total: action.payload,
};
} }
function setMineOffers(state, action) { function setMineOffers(state, action) {
return { return {
...state, ...state,
mineOffers: action.payload
}
mineOffers: action.payload,
};
} }
function setProfileOffers(state, action) { function setProfileOffers(state, action) {
return { return {
...state, ...state,
profileOffers: action.payload
profileOffers: action.payload,
};
}

function setFeaturedOffers(state, action) {
return {
...state,
pinnedOffers: action.payload
}
}
function clearFeaturedOffers(state) {
return {
...state,
pinnedOffers: []
}
}
function setOfferIndex(state, {payload}) {
return {
...state,
offerIndex: payload
}
}
function clearOfferIndex(state) {
return {
...state,
offerIndex: null,
}
}
function setOfferPage(state, {payload}) {
return {
...state,
offerPage: payload
}
}
function setFeaturedOfferPage(state, {payload}) {
return {
...state,
featuredOfferPage: payload
} }
} }

+ 76
- 2
src/store/saga/offersSaga.js ファイルの表示

import { import {
attemptAddOffer, attemptAddOffer,
attemptEditOffer, attemptEditOffer,
attemptFetchFeaturedOffers,
attemptFetchOffers, attemptFetchOffers,
attemptFetchOneOffer, attemptFetchOneOffer,
attemptRemoveOffer, attemptRemoveOffer,
} from "../../request/offersRequest"; } from "../../request/offersRequest";
import { import {
// OFFERS_ALL_FETCH,
OFFERS_FEATURED_FETCH,
OFFERS_FETCH, OFFERS_FETCH,
OFFERS_PROFILE_FETCH, OFFERS_PROFILE_FETCH,
OFFER_ADD, OFFER_ADD,
fetchProfileOffersError, fetchProfileOffersError,
removeOfferError, removeOfferError,
editOfferError, editOfferError,
clearFeaturedOffers,
// fetchAllOffersSuccess,
// fetchAllOffersError,
// setFeaturedOfferPage,
} from "../actions/offers/offersActions"; } from "../actions/offers/offersActions";
import { all, takeLatest, call, put, select } from "@redux-saga/core/effects"; import { all, takeLatest, call, put, select } from "@redux-saga/core/effects";
import { import {
} from "../actions/offers/offersActions"; } from "../actions/offers/offersActions";
import { selectUserId } from "../selectors/loginSelectors"; import { selectUserId } from "../selectors/loginSelectors";
import { import {
// selectFeaturedOfferPage,
// selectOfferPage,
selectOffers, selectOffers,
selectPinnedOffers, selectPinnedOffers,
selectTotalOffers, selectTotalOffers,
} from "../selectors/offersSelectors"; } from "../selectors/offersSelectors";
import history from "../utils/history"; import history from "../utils/history";
import { NOT_FOUND_PAGE } from "../../constants/pages"; import { NOT_FOUND_PAGE } from "../../constants/pages";
// import { KEY_PAGE } from "../../constants/queryStringConstants";

// function* fetchAllOffers(payload) {
// try {
// yield put(clearOffers());
// yield put(clearFeaturedOffers());
// const queryString = new URLSearchParams(
// convertQueryStringForBackend(payload.payload.queryString)
// );
// const page = queryString.get(KEY_PAGE);
// const offerPage = yield select(selectOfferPage)
// const featuredOfferPage = yield select(selectFeaturedOfferPage);
// const featuredOffers = yield call(
// attemptFetchFeaturedOffers,
// "?" + removePageAndSizeHelper(queryString.toString())
// );
// const newQueryString = new URLSearchParams(
// convertQueryStringForBackend(payload.payload.queryString)
// );
// const regularOffers = yield call(
// attemptFetchOffers,
// "?" + queryString.toString()
// );
// const offerIndex = featuredOffers.data.length - page * 10;
// if (page > Math.floor(featuredOffers.data.length - (page - 1) * 10)) {
// if (featuredOffers.data.length !== 0) {
// yield put(
// setPinnedOffers(
// featuredOffers.data.slice((page - 1) * 10),
// featuredOffers.data.length
// )
// );
// yield put(setOffers(regularOffers.data.items.slice()));
// }
// }
// yield put(
// setTotalOffers(regularOffers.data.total + featuredOffers.data.length)
// );
// yield put(setPinnedOffers(featuredOffers.data.items.pinnedOffers));
// yield put(fetchAllOffersSuccess());
// } catch (e) {
// yield put(fetchAllOffersError());
// yield call(console.log, e);
// }
// }


function* fetchOffers(payload) { function* fetchOffers(payload) {
try { try {
"?" + newQueryString.toString() "?" + newQueryString.toString()
); );
yield put(setTotalOffers(data.data.total)); yield put(setTotalOffers(data.data.total));
yield put(setOffers(data.data.items.regularOffers));
yield put(setPinnedOffers(data.data.items.pinnedOffers));
yield put(setOffers(data.data.offers.filter(offer => !offer.pinned)));
yield put(setPinnedOffers(data.data.offers.filter(offer => offer.pinned)));
yield put(fetchOffersSuccess());
} catch (e) {
yield put(fetchOffersError());
yield call(console.log, e);
}
}

function* fetchFeaturedOffers(payload) {
try {
yield put(clearFeaturedOffers());
const newQueryString = new URLSearchParams(
convertQueryStringForBackend(payload.payload.queryString)
);
const data = yield call(
attemptFetchFeaturedOffers,
"?" + newQueryString.toString()
);
yield put(setPinnedOffers(data.data));
yield put(fetchOffersSuccess()); yield put(fetchOffersSuccess());
} catch (e) { } catch (e) {
yield put(fetchOffersError()); yield put(fetchOffersError());
takeLatest(OFFERS_PROFILE_FETCH, fetchProfileOffers), takeLatest(OFFERS_PROFILE_FETCH, fetchProfileOffers),
takeLatest(OFFER_REMOVE, removeOffer), takeLatest(OFFER_REMOVE, removeOffer),
takeLatest(OFFER_EDIT, editOffer), takeLatest(OFFER_EDIT, editOffer),
takeLatest(OFFERS_FEATURED_FETCH, fetchFeaturedOffers),
// takeLatest(OFFERS_ALL_FETCH, fetchAllOffers),
]); ]);
} }

+ 8
- 0
src/store/selectors/offersSelectors.js ファイルの表示

offersSelector, offersSelector,
(state) => state.profileOffers (state) => state.profileOffers
) )
export const selectFeaturedOfferPage = createSelector(
offersSelector,
(state) => state.featuredOfferPage
)
export const selectOfferPage = createSelector(
offersSelector,
(state) => state.offerPage
)

+ 21
- 0
src/util/helpers/queryHelpers.js ファイルの表示

newQueryString.append(KEY_SEARCH, search.searchString ?? ""); newQueryString.append(KEY_SEARCH, search.searchString ?? "");
return newQueryString; return newQueryString;
}; };
export const changePageQueryStringHelper = (queryString, newPage) => {
const newQueryString = new URLSearchParams(queryString);
if (newQueryString.has(KEY_PAGE)) {
newQueryString.delete(KEY_PAGE);
}
newQueryString.set(KEY_PAGE, newPage);
return newQueryString.toString();
};
export const changePageQueryObjectHelper = (queryObject, newPage) => {
if (queryObject.has(KEY_PAGE)) {
queryObject.delete(KEY_PAGE);
}
queryObject.set(KEY_PAGE, newPage);
return queryObject;
};
export const removePageAndSizeHelper = (queryString) => {
const newQueryString = new URLSearchParams(queryString);
if (newQueryString.has(KEY_PAGE)) newQueryString.delete(KEY_PAGE);
if (newQueryString.has(KEY_SIZE)) newQueryString.delete(KEY_SIZE);
return newQueryString.toString();
}

+ 11
- 0
src/util/helpers/routeHelpers.js ファイルの表示

import history from "../../store/utils/history";

export const routeMatches = (route) => {
if (
history.location.pathname === route ||
history.location.pathname + "/" === route ||
history.location.pathname.slice(0, -1) === route
)
return true;
return false;
};

読み込み中…
キャンセル
保存