Unable to replace default image with image url that returns 404 in Map function in next.js - next.js

I want to display default image instead of white space
Swatch Image
for example https://cdn11.bigcommerce.com/s-hmhnh4h9/images/stencil/70w/attribute_value_images/252766.preview.jpg this return 404
while this returns 200 https://cdn11.bigcommerce.com/s-hmhnh4h9/images/stencil/70w/attribute_value_images/252738.preview.jpg
I even tried fetch method but still it has same result
I have built a function to detect if image loads or fail
`
async function getImageOrFallback(url: string, fallback: string) {
return new Promise((resolve, reject) => {
const img = new Image()
img.src = url
img.onload = () => resolve(url)
img.onerror = () => resolve(fallback);
}).catch(() => {
return fallback
})
}
`
Under swatch if image url is invalid then a default image needed to be displayed
`
<div className="option-section">
<div id="alloptions" className="flex_div flex justify-between flex-wrap flex-row py-4">
<input id="selected_variant" type="hidden" value={currentVariant.id} />
{variants.data.sort((a: any, b: any) => a.option_values[0].label.replace(/[^A-Za-z]/g, '').localeCompare(b.option_values[0].label.replace(/[^A-Za-z]/g, ''))).sort((a:any,b:any)=>{
if(a.option_values[0].label.replace(/[^A-Za-z]/g, '')[0] == b.option_values[0].label.replace(/[^A-Za-z]/g, '')[0]){
return a.option_values[0].label.replace(/[^0-9]/g, '').localeCompare(b.option_values[0].label.replace(/[^0-9]/g, ''));
}
}).sort((a:any,b:any) => {
if(variantCount < 8){
if (a.inventory_level === 0) {
return 1;
}
if (b.inventory_level === 0) {
return -1;
}
if (a.inventory_level === b.inventory_level) {
return 0;
}
return a < b ? -1 : 1;}else{
return false;
}
}).map((v: any, i: number) => {
let pUrl = product.path.replace('.html', '')
const opt = v.option_values[0]
const active = selectedOptions[opt.option_display_name.toLowerCase()]
// const swatch = v.image_url;
const swatch =
publicRuntimeConfig.COLOR_SWATCH_URL +
'/stencil/70w/attribute_value_images/' +
opt.id +
'.preview.jpg'
var imageUrl = getImageOrFallback(`${swatch}`, '/product-img-placeholder.svg').then(validUrl => {
validUrl
})
console.log("!!!!!!!!!!!!!!!! ", imageUrl)
const isDisabled = v.inventory_level == 0 ? ' color_disabled' : ' color_enabled'
const itemQty = items ? items[v.id] : 0
return (
<Swatch
key={`${opt.id}-${i}`}
active={v.sku}
variant={opt.option_display_name}
color={v.hexColors ? v.hexColors[0] : ''}
image={swatch ? swatch : ''}
label={opt.label}
id={itemQty}
className={customclass + isDisabled}
onClick={() => {
loadOptions(v);
setCurrentVariant(event, v, null);
}}
/>
)
})}
</div>
</div>
enter image description here
Under the Swatch component default image needed to display

Related

How to get values from dynamically created function component in next.js

I have a component count. It changes. I add dynamically function component as many as count.
Then I want to get values of variables.
const MainComponent: React.FC<Props> = ({ fields, label, addCount }) => {
const components = () => {
const comps = [];
for (let index = 0; index < addCount; index++) {
comps.push(<CampaignConfigurationProperty fields={fields[index]} label={label}></CampaignConfigurationProperty>);
}
return comps;
};
return (
<div>
<p>{label}</p>
<div className={styles.anotherText + " " + styles.endText + " col"}>
{components()}
</div>
</div>
);
};
export default MainComponent;
this is code i think have error but this is help you !
const MainComponent: React.FC<Props> = ({ fields, label, addCount }) => {
const [comps , setComps] = useState<any>([])
useEffect(() => {
const components = () => {
const x = []
for (let index = 0; index < addCount; index++) {
x.push({fild: fields[index]} ,label :label );
}
return comps;
};
setComps(components())
},[])
return (
<div>
<p>{label}</p>
<div className={styles.anotherText + " " + styles.endText + " col"}>
{comps.map((i , index) =>
<CampaignConfigurationProperty key={index} fields={i.fild} label={i.label} />
)}
</div>
</div>
);
};
export default MainComponent;

How to update url img in firebase

I have a todo list, where I want add some fields:
name
description
I also have two other fields to add:
icon
logo
My image is stored in firebase storage, on this level is worked well. My problem is that when I try to update the card, it only updated the name and description, but the field url remains empty. I am developing on react js and using hooks.
Where do I have an issue? How can I resolve it?
here is an example of my code
const Menu = ({ add, updateCard, contactId }) => {
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const [uploadFile, setUploadFile] = useState(null);
const [url, setImageUrl] = useState('');
const handleChange = useCallback(({ target }) => {
const { name, value } = target;
switch (name) {
case 'name':
setName(value);
break;
case 'description':
setDescription(value);
break;
case 'icon':
setUploadFile(target.files[0]);
break;
case 'logo':
setUploadFile(target.files[0]);
break;
default:
return;
}
}, []);
const resset = () => {
setName('');
setDescription('');
};
const handleSubmit = e => {
e.preventDefault();
resset();
};
useEffect(() => {
if (uploadFile?.name) {
AsynchRoneUploadFile();
}
async function AsynchRoneUploadFile() {
const storageRef = app.storage().ref('Logo');
const fileRef = storageRef.child(uploadFile?.name);
try {
await fileRef.put(uploadFile);
setImageUrl(await fileRef.getDownloadURL());
} catch (e) {
console.log(e.message);
}
}
}, [handleChange, updateCard, uploadFile]);
const buttonName = (add && 'Creat') || (updateCard && 'Update');
return (
<>
<form onSubmit={handleSubmit}>
<Form
handleChange={handleChange}
name={name}
description={description}
/>
<UploadBar onHandlechange={handleChange} />
<button
className={s.btn}
type="submit"
onClick={() =>
(add && add({ name, description, url })) ||
(updateCard &&
updateCard({
contactId,
name,
description,
url,
}))
}
>
{buttonName}
</button>
</form>
</>
);
};

Expected server HTML to contain a matching <input> in <div>

Whenever I check for the existence of the condition isAuthorized (true or false) I get this error message on the console. Basically the error refers to server-side rendering, but I can't identify where I should fix it. When i remove isAuthorized the error disappears.
I have my context, I return isAuthorized as true or false depending on the existence of the token in the cookie.
GlobalContext.js
const Global = createContext();
export function GlobalContextProvider({ children }) {
const { push } = useRouter();
const userCookie = Cookies.getJSON("user");
const [authUser, setAuthUser] = useState(() => {
if (userCookie) return userCookie;
if (!userCookie) return {};
});
const [isAuthorized, setIsAuthorized] = useState(() => {
return !authUser || Object.keys(authUser).length == 0 ? false : true;
});
useEffect(() => {
if (!isAuthorized) {
return push("/auth/login");
}
}, [isAuthorized]);
const value = {
isAuthorized,
setIsAuthorized,
authUser,
setAuthUser,
};
return <Global.Provider value={value}>{children}</Global.Provider>;
}
export const useGlobalContext = () => useContext(Global);
Index.jsx
export default function PanelLayout({ children, title }) {
const { push } = useRouter();
const { isAuthorized, setIsAuthorized } = useGlobalContext();
useEffect(() => {
const userData = Cookies.getJSON("user");
if (!userData || !userData.access_token) {
return push("/auth/login");
setIsAuthorized(false);
}
}, []);
return (
<>
{isAuthorized && (
<>
<Head>
// Content
</Head>
<input type="checkbox" id="sidebar-toggle" />
<div className="main-content">
// Content
</div>
</>
)}
</>
);
}
use this code in routes file where all the routes with components are placed.
and place this useEffect there if this condition meets give the access to that routes otherwise redirect it to login.
useEffect(() => {
const userData = Cookies.getJSON("user");
if (!userData || !userData.access_token) {
return push("/auth/login");
setIsAuthorized(false);
}
}, []);

Vue 3 Composition API broken after re-rendering the component

thanks for reading my post.
It's hard to describe my issue.
I have a reactive object cached globally(like a store and let's call it 'store' here) to preserve the states together with some actions. It's working all good initially. But when I added more pages & switching between the pages, the components are broken after re-rendering. The components can still read correctly from the store and call the actions to update the store data and can console.log the 'fingerprint' to show it's the same store. But the updated data in store is no longer updated in the UI. I can console.log the data in store which looks all good, but the UI is frozen with the data since last unmounted.
I'm providing my component code below.
<template>
<div class="min-w-full relative" ref="container">
<hi-transition slow>
<center-box
v-if="loading"
class="absolute w-full h-full left-0 top-0 text-primary-light opacity-50"
>
<hi-spinner class="w-1/6 h-1/6" :stroke="2" />LOADING...
</center-box>
<div v-else-if="noResult">
No Result
</div>
<hi-markable
v-else
class="w-full h-full divide-y divide-primary-lighter overflow-y-auto block"
:search="searchValue"
>
<div
v-for="item in displayItems"
:key="item.id"
class="hover:bg-primary-lightest transition-colors duration-500 flex items-center block"
#click="selectItem(item)"
:style="{
'min-height': minItemHeight + 'px',
height: itemHeight + 'px'
}"
:class="{ active: currentItem === item }"
>
<slot :item="item" />
</div>
</hi-markable>
</hi-transition>
</div>
</template>
<script>
import { inject, ref } from "vue";
import HiSpinner from "#/ui/HiSpinner";
import CenterBox from "#/ui/elements/CenterBox";
import HiTransition from "#/ui/HiTransition";
import HiMarkable from "#/ui/HiMarkable";
import { computed } from "vue";
export default {
name: "HiDataList",
components: { HiMarkable, HiTransition, CenterBox, HiSpinner },
props: {
storeToken: String,
minItemHeight: [Number, String],
autoItemsPerPage: Boolean
},
emits: ["select"],
setup(props, { emit }) {
//this store is a reactive object cached somewhere
const store = inject(props.storeToken);
//to make sure it's the same store
console.log("fingerprint", store.fingerprint);
const { displayItems, currentItem, loading, searchValue, noResult } = store;
const container = ref(null);
const itemHeight = computed(() => {
return props.autoItemsPerPage
? store.autoItemHeight.value
: props.minItemHeight;
});
if (props.autoItemsPerPage) {
store.autoItemsPerPage(container, props.minItemHeight);
}
function selectItem(item) {
console.log(item);
emit("select", item);
store.setCurrentItem(item);
}
return {
displayItems,
selectItem,
container,
itemHeight,
currentItem,
loading,
searchValue,
noResult
};
}
};
</script>
<style scoped>
.active,
.active:hover {
#apply bg-primary-lighter border-primary-light;
}
</style>
The listStore
import { computed, reactive, watch, toRefs } from "vue";
import { useElementSize } from "#vueuse/core";
import { watchProps } from "#/utils/reactiveHelpers";
function filter(item, filters) {
const f = (key, filter) => {
const itemVal = item[key];
if (Array.isArray(itemVal)) return itemVal.indexOf(filter) >= 0;
else return itemVal === filter;
};
for (let key in filters) {
const filterVal = filters[key];
if (Array.isArray(filterVal)) {
for (let i = 0; i < filterVal.length; i++) {
if (f(key, filterVal[i])) return true;
}
} else {
return f(key, filterVal);
}
}
return false;
}
const getTime = date => {
if (date.milliseconds) return date.milliseconds;
if (date.seconds) return date.seconds;
if (date.getTime) return date.getTime();
};
const createListStore = (source, settings = {}) => {
const state = reactive({
source: source,
currentPage: 0,
itemsPerPage: 0, //zero means display all
loading: true,
ready: false,
noData: false,
noResult: false,
filters: {},
search: null,
searchables: settings.searchables || [],
sortBy: null,
sortType: "alpha",
desc: false,
currentItem: null,
autoItemHeight: 0,
fingerprint: Math.random() * 10000000000000000
});
// const { itemsPerPage,source,filters,search,searchables,sortBy,sortType,desc } = toRefs(state);
const {
itemsPerPage,
ready,
loading,
noResult,
search,
autoItemHeight
} = toRefs(state);
watchProps(state, "source", v => {
if (typeof v !== "undefined") {
state.ready = true;
state.loading = false;
if (!v.length) state.noData = true;
}
});
const currentPage = computed(() => state.currentPage + 1);
// const itemsPerPage = computed(() => state.itemsPerPage);
const totalItems = computed(() => results.asc.length);
const from = computed(() => {
if (totalItems.value === 0) return 0;
return state.currentPage * state.itemsPerPage + 1;
});
const to = computed(() => {
const t = from.value + displayItems.value.length - 1;
return t > totalItems.value ? totalItems.value : t;
});
const totalPages = computed(() => {
if (totalItems.value === 0 || state.itemsPerPage === 0) return 1;
return Math.ceil(totalItems.value / state.itemsPerPage);
});
const gotoPage = page => {
console.log("gotoPage", page);
state.currentPage = page - 1;
console.log(state.currentPage);
};
const prevPage = () => {
if (state.currentPage > 0) state.currentPage--;
};
const nextPage = () => {
if (state.currentPage < totalPages.value) state.currentPage++;
};
const updateFilters = (filter, val) => {
state.filters[filter] = val;
};
/**
*
* #param column
* #param desc
* #param type "alpha"|"number"|"date"|"time"
*/
const sortBy = (column, desc = false, type = "alpha") => {
state.sortBy = column;
state.desc = desc;
state.sortType = type;
};
function doSearch(item) {
const searchables = state.searchables;
for (let i = 0; i < searchables.length; i++) {
const key = searchables[i];
let value = item[key];
if (value && typeof value === "string") {
value = value.toLowerCase();
}
if (value && value.indexOf(state.search) >= 0) {
return true;
}
}
return false;
}
const results = reactive({
desc: [],
asc: []
});
function calcResults() {
if (!state.ready || state.noData) return null;
// console.log("re-calc results....");
const hasFilters = Object.keys(state.filters).length > 0;
// console.log(Object.keys(state.filters));
let items = [];
if (hasFilters || (state.search && state.search.length)) {
//do filter & search
const source = state.source;
for (let i = 0; i < source.length; i++) {
const item = source[i];
// console.log(filter(item, state.filters));
if (hasFilters && !filter(item, state.filters)) {
continue;
}
if (state.search && state.search.length && !doSearch(item)) {
continue;
}
items.push(item);
}
if (!items.length) {
results.desc = results.asc = [];
return null;
}
} else {
items = state.source;
}
if (state.sortBy) {
//do sort
const sort = state.sortBy;
// const desc = state.desc ? -1 : 1;
const type = state.sortType.toLowerCase();
items.sort((a, b) => {
a = a[sort];
b = b[sort];
if (type === "date" || type === "time") {
return getTime(a) - getTime(b);
} else {
if (typeof a === "string") a = a.trim();
if (typeof b === "string") b = b.trim();
if (state.sortType.toLowerCase() === "number") {
return a - b;
} else {
return a.localeCompare(b, "en", { sensitivity: "base" });
}
}
});
}
results.asc = items;
results.desc = [...items].reverse();
// return items;
}
//changed to watch for the wired vue error.
watchProps(
state,
["source", "filters", "search", "searchables", "sortBy", "sortType"],
() => {
calcResults();
state.noResult = results.asc.length === 0;
}
);
const displayItems = computed(() => {
if (!results.asc.length) return [];
const re = state.desc ? results.desc : results.asc;
if (state.itemsPerPage === 0) return re;
const from = state.currentPage * state.itemsPerPage;
const to = from + state.itemsPerPage;
return re.slice(from, to);
});
/**
*
* #param elementRef ref
* #param minHeight Number
* #param itemHeightRef ref
*/
const autoItemsPerPage = (elementRef, minHeight) => {
const { height } = useElementSize(elementRef);
// console.log(elementRef);
watch(height, v => {
const items = Math.floor(v / minHeight);
// itemHeightRef.value = v / items;
// console.log(v / items);
state.itemsPerPage = items;
state.autoItemHeight = v / items;
});
};
const setCurrentItem = item => {
console.log("set current", state.fingerprint);
state.currentItem = item;
};
const currentItem = computed(() => state.currentItem);
return {
currentPage,
itemsPerPage,
totalItems,
displayItems,
from,
to,
totalPages,
gotoPage,
prevPage,
nextPage,
ready,
loading,
updateFilters,
sortBy,
search: v => (state.search = v),
searchValue: search,
autoItemsPerPage,
setCurrentItem,
currentItem,
noResult,
autoItemHeight,
fingerprint: state.fingerprint
};
};
export { createListStore };
The store provider
import { provide } from "vue";
import { createListStore } from "#/ui/storeProvider/listStore";
const storeDepot = {};
export const provideListStore = (token, source, settings = {}) => {
if (!storeDepot[token]) {
console.log("create new store", token);
storeDepot[token] = createListStore(source, settings);
}
provide(token, storeDepot[token]);
return storeDepot[token];
};

Can't read property 'bind' of undefined

OS: Windows 10 Pro
apollo-client: 1.9.2
react-redux: 5.0.6
So, I'm attempting to read 'connect' a graphql resultset to redux but am receiving the above mentioned error message. My code is as follows:
import { connect } from 'react-redux';
class PhotoGrid extends React.Component {
render () {
const { data } = this.props;
const isNewPage = this.props.location.pathname.includes('new');
if (data.loading) {
return <p>Loading ...</p>;
}
if (data.error) {
return <p>{data.error.message}</p>;
}
return (
<div>
<div>Total record count: {data._allPostsesMeta.count}</div>
<div className="photo-grid">
{ data.allPostses.map( (post,i) => <Photo {...this.props} key={i} postIndexID={i} post={post} />) }
</div>
{isNewPage && (
<div>
<div onClick={() => this.previousPage()}>
Previous
</div>
<div onClick={() => this.nextPage()}>
Next
</div>
</div>
)}
</div>
);
}
};
const allPostsCommentsQuery = graphql(All_Posts_Comments_Query, {
options: ownProps => {
const page = parseInt(ownProps.match.params.page, 10);
const isNewPage = ownProps.location.pathname.includes('new');
const skip = isNewPage ? (page - 1) * parseInt(PRODUCTS_PER_PAGE) : 0;
const first = isNewPage ? parseInt(PRODUCTS_PER_PAGE) : parseInt(PRODUCTS_PER_PAGE);
const orderBy = isNewPage ? OrderBy : null;
fetchPolicy: 'network-only';
return {
variables: {
__offline__: true,
first,
skip,
orderBy,
},
}
},
});
export default connect(allPostsCommentsQuery)(PhotoGrid)
What am I overlooking here?

Resources