App reviews, troubleshooting, and recommendations
We're moving the community! Starting July 7, the current community will be read-only for approx. 2 weeks. You can browse content, but posting will be temporarily unavailable. Learn more
Hi there,
I am using CLI 3 to make my client a Shopify Checkout Extension app I have made a count down Timer for but there is a issue that I am not able resolve, The timer is working fine but when I reload the page or go to the next step of checkout the timer restarts I am storing data in session storage but that does seem to be working I have also tried to store data in cookie, local storage and even cache storage but none of them seem to work. Can some one guide me how to accomplish this task?
import React, { useEffect, useState } from 'react'; import { render, BlockStack, Text, useSettings, View } from '@shopify/checkout-ui-extensions-react'; render('Checkout::Dynamic::Render', () => <App />); function App() { const { timer_before_text, timer_after_text, timer, timer_ends, timer_text_color, timer_text_size, timer_size, timer_color } = useSettings(); const calculateEndTime = (timer) => { const currentTime = new Date(); const endTime = new Date(currentTime.getTime() + timer * 60000); // Convert minutes to milliseconds return endTime; }; const getRemainingTimeInSeconds = (endTime) => { const currentTime = new Date(); const remainingTimeInSeconds = Math.floor((endTime - currentTime) / 1000); return remainingTimeInSeconds >= 0 ? remainingTimeInSeconds : 0; }; const setCookie = (name, value, days) => { const expirationDate = new Date(); expirationDate.setTime(expirationDate.getTime() + days * 24 * 60 * 60 * 1000); document.cookie = `${name}=${value}; expires=${expirationDate.toUTCString()}; path=/`; }; const getCookie = (name) => { const cookieName = `${name}=`; const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { let cookie = cookies[i]; while (cookie.charAt(0) === ' ') { cookie = cookie.substring(1); } if (cookie.indexOf(cookieName) === 0) { return cookie.substring(cookieName.length, cookie.length); } } return ''; }; const deleteCookie = (name) => { document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`; }; const [seconds, setSeconds] = useState(0); useEffect(() => { const storedEndTime = getCookie('endTime'); let endTime; if (storedEndTime) { endTime = new Date(storedEndTime); // If the stored end time has already passed, clear it and recalculate the end time if (endTime <= new Date()) { deleteCookie('endTime'); endTime = calculateEndTime(isNaN(timer) ? +timer : timer); // Set the timer to 15 minutes } } else { endTime = calculateEndTime(isNaN(timer) ? +timer : timer); // Set the timer to 15 minutes setCookie('endTime', endTime.toUTCString(), 1); } setSeconds(getRemainingTimeInSeconds(endTime)); const interval = setInterval(() => { setSeconds((prevSeconds) => { if (prevSeconds <= 0) { clearInterval(interval); // Stop the timer deleteCookie('endTime'); return 0; } return prevSeconds - 1; }); }, 1000); return () => { clearInterval(interval); }; }, []); const formattedTime = React.useMemo(() => { const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; }, [seconds]); return ( <BlockStack border="base" borderRadius="base" padding="tight" spacing="loose" blockAlignment="center" cornerRadius="loose" overflow="hidden" inlineAlignment="center" > <View> <Text size={timer_text_size} appearance={timer_text_color} emphasis="strong"> {timer_before_text} </Text> {seconds > 0 ? ( <Text size={timer_size} emphasis="strong" appearance={timer_color}> {formattedTime} </Text> ) : ( <Text size={timer_size} appearance={timer_color} emphasis="strong"> {timer_ends} </Text> )} <Text size={timer_text_size} appearance={timer_text_color} emphasis="strong"> {timer_after_text} </Text> </View> </BlockStack> ); } export default App;
Solved! Go to the solution
This is an accepted solution.
Turned out that we can not use Cookies or localStorage in UI Extension instead Shopify gives us an storage function that works similar to cookies and local storage. You can use storage function to store data and retrieve it.
const { timer } = useSettings();
const { storage } = useApi(); // useApi gives access to store data like session storage
const [counterTimer, setCounterTimer] = useState(timer * 60); // Initial timer value set to the value from useSettings();
const interval = setInterval(() => {
setCounterTimer((prevTimer) => {
if (prevTimer > 0) {
const newTimer = prevTimer - 1;
storage
.write('countdownTimer', newTimer)
.catch((error) => console.error('Error while writing timer data:', error));
return newTimer;
} else {
clearInterval(interval);
storage
.delete('countdownTimer')
.catch((error) => console.error('Error while deleting timer data:', error));
return 0;
}
});
}, 1000);
return () => {
clearInterval(interval);
};
}, [storage]);
The code seems to be the same and I'm still having trouble with Shopify session Token 😢
This is an accepted solution.
Turned out that we can not use Cookies or localStorage in UI Extension instead Shopify gives us an storage function that works similar to cookies and local storage. You can use storage function to store data and retrieve it.
const { timer } = useSettings();
const { storage } = useApi(); // useApi gives access to store data like session storage
const [counterTimer, setCounterTimer] = useState(timer * 60); // Initial timer value set to the value from useSettings();
const interval = setInterval(() => {
setCounterTimer((prevTimer) => {
if (prevTimer > 0) {
const newTimer = prevTimer - 1;
storage
.write('countdownTimer', newTimer)
.catch((error) => console.error('Error while writing timer data:', error));
return newTimer;
} else {
clearInterval(interval);
storage
.delete('countdownTimer')
.catch((error) => console.error('Error while deleting timer data:', error));
return 0;
}
});
}, 1000);
return () => {
clearInterval(interval);
};
}, [storage]);
Can someone take this a combine it into a real answer? I just want to create a countdown clock module and there are no examples on the net for how to do this as a shopify checkout extension. It's so dumb this whole process should be thrown away by shopify. Checkout UI extensions are the dumbest thing on the planet. You have this nice ecosystem surrounding liquid and json...and you've thrown it all away to catch the bandwagon with react. Its dumb its complicated and unnecessary on merchants and developers.