just having issues with populating the JSON into my chart. I'm seeing the response in the console log with API status with no errors, but for some reason, it's not populating it. Using Axios to fetch the example API to populate the emp sal and age. I have a feeling that I need to move the "UseEffect" somewhere but not sure where that needs to go.
import React, { useState, useEffect } from "react";
import { Link } from 'react-router-dom';
import LineChart from '../../charts/LineChart01';
import Icon from '../../images/icon-01.svg';
import EditMenu from '../EditMenu';
import axios from "axios";
// Import utilities
import { tailwindConfig, hexToRGB } from '../../utils/Utils';
const DashboardCard01 = () => {
const [chartData, setChartData] = useState({});
const [employeeSalary, setEmployeeSalary] = useState([]);
const [employeeAge, setEmployeeAge] = useState([]);
const chart = () => {
let empSal = [];
let empAge = [];
axios
.get("http://dummy.restapiexample.com/api/v1/employees")
.then(res => {
console.log(res);
for (const dataObj of res.data.data) {
empSal.push(parseInt(dataObj.employee_salary));
empAge.push(parseInt(dataObj.employee_age));
}
setChartData({
labels: empAge,
datasets: [
{
label: empAge,
data: empSal,
//backgroundColor: ["rgba(75, 192, 192, 0.6)"],
borderWidth: 4
}
]
});
})
.catch(err => {
console.log(err);
});
console.log(empSal, empAge);
datasets: [
// Indigo line
{
data: empAge,
fill: true,
backgroundColor: `rgba(${hexToRGB(tailwindConfig().theme.colors.blue[500])}, 0.08)`,
borderColor: tailwindConfig().theme.colors.indigo[500],
borderWidth: 2,
tension: 0,
pointRadius: 0,
pointHoverRadius: 3,
pointBackgroundColor: tailwindConfig().theme.colors.indigo[500],
clip: 20,
},
// Gray line
{
data: empSal,
borderColor: tailwindConfig().theme.colors.slate[300],
borderWidth: 2,
tension: 0,
pointRadius: 0,
pointHoverRadius: 3,
pointBackgroundColor: tailwindConfig().theme.colors.slate[300],
clip: 20,
},
]
};
useEffect(() => {
chart();
}, []);
return (
<div className="flex flex-col col-span-full sm:col-span-6 xl:col-span-4 bg-white shadow-lg rounded-sm border border-slate-200">
<div className="px-5 pt-5">
<header className="flex justify-between items-start mb-2">
{/* Icon */}
<img src={Icon} width="32" height="32" alt="Icon 01" />
{/* Menu button */}
<EditMenu className="relative inline-flex">
<li>
<Link className="font-medium text-sm text-slate-600 hover:text-slate-800 flex py-1 px-3" to="#0">Option 1</Link>
</li>
<li>
<Link className="font-medium text-sm text-slate-600 hover:text-slate-800 flex py-1 px-3" to="#0">Option 2</Link>
</li>
<li>
<Link className="font-medium text-sm text-rose-500 hover:text-rose-600 flex py-1 px-3" to="#0">Remove</Link>
</li>
</EditMenu>
</header>
<h2 className="text-lg font-semibold text-slate-800 mb-2">Acme Plus</h2>
<div className="text-xs font-semibold text-slate-400 uppercase mb-1">Sales</div>
<div className="flex items-start">
<div className="text-3xl font-bold text-slate-800 mr-2">$24,780</div>
<div className="text-sm font-semibold text-white px-1.5 bg-green-500 rounded-full">+49%</div>
</div>
</div>
{/* Chart built with Chart.js 3 */}
<div className="grow">
{/* Change the height attribute to adjust the chart height */}
<LineChart data={chartData} width={389} height={128} />
</div>
</div>
);
}
export default DashboardCard01;
Related
I have an app in React Native and I can only see half of my app on the android phone, the components show up on the web version.
There have been many suggestions made on Stack Overflow which do not work for me, not limited to:
flex grow 1
flex 1
onStartShouldSetResponder={() => true}
import { ScrollView } from 'react-native-gesture-handler';
Wrapping ScrollView in a View component
nestedScrollEnabled={true}
Is there a way to force scroll or android or is it just impossible?
Here is the code:
import { StyleSheet, Text, View, TextInput, Pressable, ScrollView } from 'react-native';
import {useState, useEffect} from 'react'
import axios from 'axios'
import SelectDropdown from 'react-native-select-dropdown'
import { Formik } from 'formik'
export default function App() {
const [price, setPrice] = useState();
const options = ["ARS", "ARD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK", "EUR", "GBP", "HKD", "HRK", "HUF", "INR", "ISK", "JPK", "KRW", "NZD", "PLN", "RON", "RUB", "SEK", "SGD", "THB", "TRY", "TWD", "USD"]
const [selected, setSelected] = useState(options[0])
const [amount, setAmount] = useState('')
const [calculatedAmount, setCalculatedAmount] = useState()
useEffect(() => {
axios.get('https://blockchain.info/ticker')
.then(data => {
setPrice(data)
})
}, [])
const fetchData = () => {
axios.get(`https://blockhain.info/tobtc?currency=${selected}&value=${amount}`)
.then(data => {
setCalculatedAmount(data.data)
console.log(calculatedAmount)
})
}
const handleSubmit = (e) => {
e.preventDefault()
fetchData()
}
const handleAmountChange = (e) => {
e.preventDefault()
setAmount(e.target.value)
}
if (!price || price === undefined ) {
return null
}
const Form = ({ onSubmit }) => {
<View>
<Text className="py-10 text-xl">Enter value: <TextInput className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" id="amount" placeholder="Enter value in selected currency" value={amount} onChange={handleAmountChange} data-cy="amount"></TextInput></Text>
<Text className="text-center"><Pressable className="p-5 mb-2 mr-2 overflow-hidden text-2xl text-gray-900 rounded-lg group bg-gradient-to-br from-purple-600 to-blue-500 group-hover:from-purple-600 group-hover:to-blue-500 hover:text-white text-black font-bold focus:ring-4 focus:outline-none focus:ring-blue-300 dark:focus:ring-blue-800" id="convert-button" type="submit"><Text>Calculate!</Text></Pressable></Text>
<Text id="#calculatedamount" className="text-xl py-8 bg-gray-100 px-2 font-bold rounded-md" data-cy="submit">Value: {calculatedAmount} BTC</Text>
</View>
}
return (
<ScrollView className="h-screen bg-blue-100" nestedScrollEnabled={true}>
<View className="py-10">
<Text className="text-xl text-center m-auto text-black font-bold">Current Prices</Text>
</View>
<View className="md:flex justify-around h-full">
<View className="text-center text-2xl m-auto bg-gray-100 p-20 rounded-md shadow-2xl max-w-[75%]">
<Text className="text-md font-bold">(£) {price.data.GBP.symbol} {price.data.GBP.last} BTC</Text>
</View>
<View className="text-center text-2xl m-auto bg-gray-100 p-20 rounded-md shadow-2xl max-w-[75%]">
<Text className="text-md font-bold">(€) {price.data.EUR.symbol} {price.data.EUR.last} BTC</Text>
</View>
<View className="text-center text-2xl m-auto bg-gray-100 p-20 rounded-md shadow-2xl max-w-[75%]">
<Text className="text-md font-bold">($) {price.data.USD.symbol} {price.data.USD.last} BTC</Text>
</View>
</View>
<View className="h-screen flex ">
<View className="m-auto bg-blue-300 p-20 rounded-md shadow-2xl">
<Text className="text-3xl font-bold py-10">Convert Currency into BTC</Text>
<Text className="text-xl"> Select a currency: <SelectDropdown className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
id='currency'
value={selected}
data-cy="select"
onChange={(e) => setSelected(e.target.value)}>
{options.map((value) => (<Text>
<Text value={value} key={value}>
<Text> {value}</Text>
</Text>
</Text>))}
</SelectDropdown></Text>
<Formik initialValues={{ amount: '' }} onSubmit={handleSubmit}>
{({ handleSubmit }) => <Form onSubmit={handleSubmit} />}
</Formik>
</View>
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
I am trying to replicate the scroll functionality (both video and text) from this website, except my video is a long lottie file.
I am using the following frameworks: Nextjs, React, Tailwind
The code below is after many failed attempts. I'm unable to keep the lottie fixed and make it look like one continuous animation. When the position is sticky/fixed it isn't animated on scroll for some reason. Would really appreciate some help. Thank you.
import Head from 'next/head'
import backgroundImage from '#/images/background-faqs.jpg'
import Image from 'next/future/image'
import { CallToAction } from '#/components/CallToAction'
import { Faqs } from '#/components/Faqs'
import { Footer } from '#/components/Footer'
import { Header } from '#/components/Header'
import { Hero } from '#/components/Hero'
import { Pricing } from '#/components/Pricing'
import { PrimaryFeatures } from '#/components/PrimaryFeatures'
import { SecondaryFeatures } from '#/components/SecondaryFeatures'
import { testimonials } from '#/components/testimonials'
import React, { useState } from 'react'
import { useLottie, useLottieInteractivity } from 'lottie-react'
import likeButton from '../images/lottie.json'
const options = {
animationData: likeButton,
}
const LottieAnimation = () => {
const lottieObj = useLottie(options)
const Animation = useLottieInteractivity({
lottieObj,
mode: 'scroll',
container: 'lottie_container',
actions: [
{
visibility: [0, 0.3],
type: 'stop',
frames: [0],
},
{
visibility: [0.3, 0.7],
type: 'seek',
frames: [0, 100],
},
{
visibility: [0.7, 1.0],
type: 'stop',
frames: [100],
},
],
})
return Animation
}
const LottieAnimation2 = () => {
const lottieObj = useLottie(options)
const Animation = useLottieInteractivity({
lottieObj,
mode: 'scroll',
container: 'lottie_container',
actions: [
{
visibility: [0, 0.3],
type: 'stop',
frames: [100],
},
{
visibility: [0.3, 0.7],
type: 'seek',
frames: [100, 107],
},
{
visibility: [0.7, 1.0],
type: 'stop',
frames: [107],
},
],
})
return Animation
}
const LottieAnimation3 = () => {
const lottieObj = useLottie(options)
const Animation = useLottieInteractivity({
lottieObj,
mode: 'scroll',
container: 'lottie_container',
actions: [
{
visibility: [0, 0.3],
type: 'stop',
frames: [107],
},
{
visibility: [0.4, 0.6],
type: 'seek',
frames: [107, 115],
},
{
visibility: [0.7, 1.0],
type: 'stop',
frames: [115],
},
],
})
return Animation
}
const LottieAnimation4 = () => {
const lottieObj = useLottie(options)
const Animation = useLottieInteractivity({
lottieObj,
mode: 'scroll',
container: 'lottie_container',
actions: [
{
visibility: [0, 0.3],
type: 'stop',
frames: [0],
},
{
visibility: [0.4, 0.6],
type: 'seek',
frames: [0, 100],
},
{
visibility: [0.7, 1.0],
type: 'seek',
frames: [100, 0],
},
],
})
return Animation
}
const LottieAnimation5 = () => {
const lottieObj = useLottie(options)
const Animation = useLottieInteractivity({
lottieObj,
mode: 'scroll',
container: 'lottie_container',
actions: [
{
visibility: [0, 0.3],
type: 'stop',
frames: [0],
},
{
visibility: [0.4, 0.6],
type: 'seek',
frames: [0, 100],
},
{
visibility: [0.7, 1.0],
type: 'seek',
frames: [100, 0],
},
],
})
return Animation
}
export default function Home() {
return (
<>
<div class="absolute inset-x-0 top-[-10rem] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[-20rem]">
<svg
class="relative left-[calc(50%-11rem)] -z-10 h-[21.1875rem] max-w-none -translate-x-1/2 rotate-[30deg] sm:left-[calc(50%-30rem)] sm:h-[42.375rem]"
viewBox="0 0 1155 678"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="url(#45de2b6b-92d5-4d68-a6a0-9b9b2abad533)"
fill-opacity=".25"
d="M317.219 518.975L203.852 678 0 438.341l317.219 80.634 204.172-286.402c1.307 132.337 45.083 346.658 209.733 145.248C936.936 126.058 882.053-94.234 1031.02 41.331c119.18 108.451 130.68 295.337 121.53 375.223L855 299l21.173 362.054-558.954-142.079z"
/>
<defs>
<linearGradient
id="45de2b6b-92d5-4d68-a6a0-9b9b2abad533"
x1="1155.49"
x2="-78.208"
y1=".177"
y2="474.645"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#9089FC"></stop>
<stop offset="1" stop-color="#FF80B5"></stop>
</linearGradient>
</defs>
</svg>
</div>
<Head>
<title>name</title>
<meta name="description" content="need to fill" />
</Head>
<Header />
<main>
<div>
<Hero />
<div class="absolute inset-x-0 top-[calc(100%-13rem)] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[calc(100%-30rem)]">
<svg
class="relative left-[calc(50%+3rem)] h-[21.1875rem] max-w-none -translate-x-1/2 sm:left-[calc(50%+36rem)] sm:h-[42.375rem]"
viewBox="0 0 1155 678"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="url(#ecb5b0c9-546c-4772-8c71-4d3f06d544bc)"
fill-opacity=".3"
d="M317.219 518.975L203.852 678 0 438.341l317.219 80.634 204.172-286.402c1.307 132.337 45.083 346.658 209.733 145.248C936.936 126.058 882.053-94.234 1031.02 41.331c119.18 108.451 130.68 295.337 121.53 375.223L855 299l21.173 362.054-558.954-142.079z"
/>
<defs>
<linearGradient
id="ecb5b0c9-546c-4772-8c71-4d3f06d544bc"
x1="1155.49"
x2="-78.208"
y1=".177"
y2="474.645"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#9089FC"></stop>
<stop offset="1" stop-color="#FF80B5"></stop>
</linearGradient>
</defs>
</svg>
</div>
</div>
<div id="lottie_container" class="flex scroll-smooth">
<div class="ml-auto inline-block w-full md:w-5/12">
<div class="flex h-screen flex-col items-center justify-center">
<LottieAnimation />
</div>
<div class="flex h-screen flex-col items-center justify-center">
<LottieAnimation2 />
</div>
<div class="flex h-screen flex-col items-center justify-center">
<LottieAnimation3 />
</div>
<div class="flex h-screen flex-col items-center justify-center">
<LottieAnimation4 />
</div>
<div class="flex h-screen flex-col items-center justify-center">
<LottieAnimation5 />
</div>
</div>
<div class="ml-auto inline-block w-full md:w-5/12">
<div class="flex h-screen flex-col items-center justify-center">
<h2 class="mb-5 text-4xl">Animation 1</h2>
<p class="mb-5">description</p>
</div>
<div class="flex h-screen flex-col items-center justify-center">
<h2 class="mb-5 text-4xl">Animation 2</h2>
<p class="mb-5">description</p>
</div>
<div class="flex h-screen flex-col items-center justify-center">
<h2 class="mb-5 text-4xl">Animation 3</h2>
<p class="mb-5">description</p>
</div>
<div class="flex h-screen flex-col items-center justify-center">
<h2 class="mb-5 text-4xl">Animation 4</h2>
<p class="mb-5">description</p>
</div>
<div class="flex h-screen flex-col items-center justify-center">
<h2 class="mb-5 text-4xl">Animation 5</h2>
<p class="mb-5">description</p>
</div>
</div>
</div>
<PrimaryFeatures />
<SecondaryFeatures />
<CallToAction />
<testimonials />
<Pricing />
<Faqs />
</main>
<Footer />
</>
)
}
I'm having trouble here when I want to put chart data at the beginning.
So, before the user clicks on the name "province", the chart will first display provincial data.
Then, the user clicks on the province name, the chart will change the previous chart data to city chart data. like this
However, I am stuck here, displaying the initial chart data, namely provincial chart data.
Please help me to solve my current problem, that is, displaying province charts before changing to city charts. Thank you
My Code
import React, { useState, useEffect, useRef } from "react";
import {
Accordion,
AccordionItem,
AccordionItemHeading,
AccordionItemButton,
AccordionItemPanel,
} from "react-accessible-accordion";
import { MdKeyboardArrowDown } from "react-icons/md";
import {
getStreetDallProvinsi,
// getStreetImageDallProvinsi,
getStreetallKota,
getStreetallKecamatan,
getStreetallKelurahan,
} from "../../../service/building";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
} from "chart.js";
import { Bar } from "react-chartjs-2";
import SearchComponent from "./SearchPoi";
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend
);
const Data = () => {
const [filterdata, setFilterdata] = useState([]);
const [query, setQuery] = useState("");
const [dataProvinsi, setDataProvinsi] = useState([]);
const [dataKota, setDataKota] = useState([]);
const [dataKecamatan, setDataKecamatan] = useState([]);
const [dataKelurahan, setDataKelurahan] = useState([]);
// const [dataImageProvinsi, setDataImageProvinsi] = useState([]);
const [dataChart, setDataChart] = useState();
const [isLoading, setIsLoading] = useState(false);
const [isLoadingKota, setIsLoadingKota] = useState(false);
const [isLoadingKecamatan, setIsLoadingKecamatan] = useState(false);
const provinsiRef = useRef([]);
const kotaRef = useRef([]);
const kecamatanRef = useRef([]);
const getDataAllProvinsi = () => {
setIsLoading(true);
getStreetDallProvinsi()
.then((resolve) => {
setDataProvinsi(resolve);
setFilterdata(resolve);
console.log(resolve);
})
.catch((reject) => {
console.log(reject);
})
.finally(setIsLoading(false));
};
const handlesearch = (event) => {
const getSearch = event.target.value;
if (getSearch.length > 0) {
const searchdata = dataProvinsi.filter((item) =>
item.provinsi.toLowerCase().includes(event.target.value.toLowerCase())
);
setDataProvinsi(searchdata);
} else {
setDataProvinsi(filterdata);
}
setQuery(getSearch);
};
// const getDataImageAllProvinsi = () => {
// setIsLoading(true);
// getStreetImageDallProvinsi()
// .then((resolve) => {
// setDataImageProvinsi(resolve);
// console.log();
// })
// .catch((reject) => {
// console.log(reject);
// })
// .finally(setIsLoading(false));
// };
const handleProvinsi = async (index) => {
try {
const provinsi = provinsiRef.current[index].dataset.prov;
setIsLoading(true);
const result = await getStreetallKota(provinsi);
setDataKota(result);
setDataChart(state.data.dataKota);
console.log(result);
} catch (error) {
console.log("salah")
} finally {
setIsLoading(false);
}
};
const handleKota = async (provinsi, index) => {
try {
const kota = kotaRef.current[index].dataset.city;
setIsLoadingKota(true);
const result = await getStreetallKecamatan(provinsi, kota);
setDataKecamatan(result);
setDataChart(state.data.dataKecamatan);
console.log(result);
} catch (error) {
console.log("salah")
} finally {
setIsLoadingKota(false);
}
};
const handleKecamatan = async (provinsi, kota, index) => {
try {
const kecamatan = kecamatanRef.current[index].dataset.camat;
setIsLoadingKecamatan(true);
const result = await getStreetallKelurahan(provinsi, kota, kecamatan);
setDataKelurahan(result);
console.log(result);
} catch (error) {
console.log("salah")
console.log(error)
} finally {
setIsLoadingKecamatan(false);
}
};
useEffect(() => {
getDataAllProvinsi();
// getDataImageAllProvinsi();
}, [dataChart]);
const colorCode = "#0066FF";
const colorFont = "#8E9093";
const state = {
data: {
dataProv: {
labels: dataProvinsi.map((o) => o.provinsi),
datasets: [
{
fill: true,
label: null,
backgroundColor: colorCode,
borderColor: colorCode,
borderWidth: 2,
borderRadius: 12,
data: dataProvinsi.map((o) => o.total_street),
},
],
},
dataKota: {
labels: dataKota.map((o) => o.kota),
datasets: [
{
fill: true,
label: null,
backgroundColor: colorCode,
borderColor: colorCode,
borderWidth: 2,
borderRadius: 12,
data: dataKota.map((o) => o.total_street),
},
],
},
dataKecamatan: {
labels: dataKecamatan.map((o) => o.kecamatan),
datasets: [
{
fill: true,
label: null,
backgroundColor: colorCode,
borderColor: colorCode,
borderWidth: 2,
borderRadius: 12,
data: dataKecamatan.map((o) => o.total_street),
},
],
},
},
options: {
plugins: {
legend: {
display: false,
labels: {
font: {
color: colorFont,
},
},
},
},
scales: {
x: {
grid: {
display: false,
},
beginAtZero: false,
ticks: {
color: colorFont,
},
},
y: {
grid: {
display: false,
},
beginAtZero: true,
ticks: {
color: colorFont,
},
},
},
},
};
const plugins = [
{
beforeDraw: function (chart) {
if (chart.chartArea) {
let ctx = chart.ctx;
let chartArea = chart.chartArea;
let barArray = chart.getDatasetMeta(0).data;
ctx.fillStyle = "#B2D1FF85";
for (let i = 0; i < barArray.length; i++) {
const { x, width } = barArray[i];
ctx.fillRect(
x - width / 2,
chartArea.top,
width,
chartArea.bottom - chartArea.top
);
}
}
},
},
];
return (
<>
<div className="mx-auto mt-8 w-[70rem] h-[32rem] bg-white px-5 py-3 md:px-8 md:py-5 rounded-xl drop-shadow-xl">
<h1 className="font-bold text-lg mb-4">Diagram Data</h1>
<Bar
type={"bar"}
height={120}
data={state.data.dataKota}
options={state.options}
plugins={plugins}
/>
</div>
<div className="mx-auto my-8 w-[70rem] bg-white px-5 py-3 md:px-8 md:py-5 rounded-md drop-shadow-xl">
<SearchComponent value={query} onChange={(e) => handlesearch(e)} />
<div className="flex justify-between mt-6">
<h3 className="font-bold">Nama Daerah</h3>
<div className="flex gap-8">
<h3 className="font-bold">TOTAL IMAGE</h3>
<h3 className="font-bold">TOTAL LABELLING</h3>
</div>
</div>
<Accordion allowZeroExpanded>
{dataProvinsi.map((provinsi, index) => (
<AccordionItem className="p-1" key={index}>
<AccordionItemHeading
onClick={() => {
handleProvinsi(index);
}}
>
<AccordionItemButton>
<div className="w-full inline-flex justify-between items-center">
<div className="inline-flex items-center gap-2">
<div>
<MdKeyboardArrowDown size={20} />
</div>
<div
ref={(ref) => provinsiRef.current.push(ref)}
data-prov={provinsi?.provinsi}
>
{provinsi?.provinsi}
</div>
</div>
<div>{provinsi?.total_street}</div>
</div>
</AccordionItemButton>
</AccordionItemHeading>
<AccordionItemPanel className="ml-4">
<Accordion className="flex flex-col gap-2" allowZeroExpanded>
{isLoading
? "Loading ... "
: dataKota.map((kota, index) => (
<AccordionItem className="p-1" key={kota?.id}>
<AccordionItemHeading
onClick={() => {
handleKota(provinsi?.provinsi, index);
}}
>
<AccordionItemButton>
<div className="w-full inline-flex justify-between items-center">
<div className="inline-flex items-center gap-2">
<div>
<MdKeyboardArrowDown size={20} />
</div>
<div
ref={(ref) => kotaRef.current.push(ref)}
data-city={kota?.kota}
>
{kota?.kota}
</div>
</div>
<div>{kota?.total_street}</div>
</div>
</AccordionItemButton>
</AccordionItemHeading>
<AccordionItemPanel className="ml-8">
<Accordion
className="flex flex-col gap-2"
allowZeroExpanded
>
{isLoadingKota
? "Loading..."
: dataKecamatan.map((kecamatan, index) => (
<AccordionItem
className="p-1"
key={kecamatan?.id}
>
<AccordionItemHeading
onClick={() => {
handleKecamatan(
provinsi?.provinsi, kota?.kota,
index
);
}}
>
<AccordionItemButton>
<div className="w-full inline-flex justify-between items-center">
<div className="inline-flex items-center gap-2">
<div>
<MdKeyboardArrowDown
size={20}
/>
</div>
<div
ref={(ref) => kecamatanRef.current.push(ref)}
data-camat={kecamatan?.kecamatan}
>
{kecamatan?.kecamatan}
</div>
</div>
<div>{kecamatan?.total_street}</div>
</div>
</AccordionItemButton>
</AccordionItemHeading>
<AccordionItemPanel className="ml-12">
<Accordion
className="flex flex-col gap-2"
allowZeroExpanded
>
{isLoadingKecamatan
? "Loading..."
: dataKelurahan.map(
(item, index) => (
<AccordionItem
className="p-1"
key={index}
>
<AccordionItemHeading>
<AccordionItemButton>
<div className="w-full inline-flex justify-between items-center">
<div className="inline-flex items-center gap-2">
<div>
<MdKeyboardArrowDown
size={20}
/>
</div>
<div>
{item?.kelurahan}
</div>
</div>
<div>
{item?.total_street}
</div>
</div>
</AccordionItemButton>
</AccordionItemHeading>
</AccordionItem>
)
)}
</Accordion>
</AccordionItemPanel>
</AccordionItem>
))}
</Accordion>
</AccordionItemPanel>
</AccordionItem>
))}
</Accordion>
</AccordionItemPanel>
</AccordionItem>
))}
</Accordion>
</div>
</>
);
};
export default Data;
I found some error when I deploy my app in Vercel. I am displaying a map using MapBox with "react-map-gl" library, in React and Next.js.
The MapBox work fine in local but not displaying in Prod. I can see the Popup and the Markers but not the map (it only shows a gray background).
What could possibly be the problem ?
import { useState, useEffect } from 'react';
import ReactMapGL, { Marker, Popup } from 'react-map-gl';
import getCenter from 'geolib/es/getCenter';
import Image from "next/image"
import Link from "next/link"
function Map({ coordinates, marker }) {
const [viewport, setViewport] = useState({
width: '100%',
height: '100%',
latitude: coordinates.latitude,
longitude: coordinates.longitude,
zoom: coordinates.zoom
});
console.log(marker)
useEffect(() => {
let centeredCoordinate = getCenter(coordinates.length >= 1 ?
coordinates.map(result => { return { latitude: result.latitude, longitude: result.longitude } }) :
{ latitude: 47.15025576066852, longitude: 2.032816514216602, zoom: 5 })
;
if (coordinates.length > 1) {
return setViewport({
width: '100%',
height: '100%',
latitude: centeredCoordinate.latitude,
longitude: centeredCoordinate.longitude,
zoom: 5
})
}
setViewport({
width: '100%',
height: '100%',
latitude: centeredCoordinate.latitude,
longitude: centeredCoordinate.longitude,
zoom: 13
})
}, [coordinates]);
console.log(marker)
return <ReactMapGL
{...viewport}
mapStyle='mapbox://styles/kamarov/ckuiomg715hg317qly3n8zoml'
mapboxApiAccessToken={process.env.MAPBOX_KEY}
onViewportChange={(viewport) => setViewport(viewport)}
>
{coordinates.map(result => (
<div key={result.longitude}>
<Marker
longitude={result.longitude}
latitude={result.latitude}
offsetLeft={-20}
offsetTop={-10}
>
{result.entity.isPremium ?
<p className="text-xl cursor-pointer z-90">⭐</p> :
<p className="text-xl cursor-pointer z-90">📍</p>}
</Marker>
{marker?.map(mark => (
<Popup className="rounded-xl " closeButton={false} latitude={mark.latitude} longitude={mark.longitude}>
{mark.entity.isPremium ?
<div className="flex items-center p-1 justify-between space-x-2">
<div className="w-16 h-12 relative">
<Image src={mark.entity.logo} layout="fill" objectFit="contain" />
</div>
<div className="flex flex-col">
<p className="font-content text-md text-primary">{mark.entity.longName}</p>
<Link href={"/etablissements/" + mark.entity.slug}>
<a className="mr-auto text-sm text-contrast font-content underline hover:text-primary duration-300">
Voir l'établissement
</a></Link>
</div>
</div> :
<div className="flex flex-col justify-center">
<p className="font-content text-md text-primary">{mark.entity.longName}</p>
<Link href={"/etablissements/" + mark.entity.slug}>
<a className="mr-auto text-sm text-contrast font-content underline hover:text-primary duration-300">
Voir l'établissement
</a></Link>
</div>}
</Popup>
))}
</div>
))}
</ReactMapGL>
}
export default Map
I saw in other questions that the solution was to add :
/* eslint-disable import/no-webpack-loader-syntax */
import mapboxgl from 'mapbox-gl';
// #ts-ignore
mapboxgl.workerClass = require('worker-loader!mapbox-gl/dist/mapbox-gl-csp-worker').default;
But it's not working for me as I am using react-map-gl..
Here are the errors showing in the console of the browser in the PROD (the local browser is not showing any error)
Found the solution in my next.config.js I had to remove :
swcMinify: true
And it works just fine in production.
I reused the promotion-slider.js swiper code in another FlashDealsProducts.js file with
some changes but without any error both components slides in same direction when I click
either of the slide button. I tried changing the id but it didn't worked.
Deleted dummy data of both file
Promotion-Slider.js file
import { ArrowNext, ArrowPrev } from "#components/icons";
import SwiperCore, { Navigation } from "swiper";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/swiper-bundle.css";
const offerSliderBreakpoints = {
320: {
slidesPerView: 1,
spaceBetween: 0,
},
580: {
slidesPerView: 2,
spaceBetween: 16,
},
1024: {
slidesPerView: 3,
spaceBetween: 16,
},
1920: {
slidesPerView: 4,
spaceBetween: 24,
},
};
SwiperCore.use([Navigation]);
export default function PromotionSlider() {
return (
<div className="px-6 py-5 md:px-8 xl:px-12 md:py-10 border-t border-gray-200">
<div className="relative">
<Swiper
// id="offer"
loop={true}
breakpoints={offerSliderBreakpoints}
navigation={{
nextEl: ".next",
prevEl: ".prev",
}}
>
{data?.map((d) => (
<SwiperSlide key={d.id}>
<img
className="w-full h-auto"
src={d.bannerUrl}
alt={d.title}
width="430"
height="200"
/>
</SwiperSlide>
))}
</Swiper>
<div
className="prev cursor-pointer absolute top-2/4 -left-4 md:-left-5 z-10 -mt-4 md:-mt-5 w-8 h-8 md:w-9 md:h-9 rounded-full bg-white shadow-xl border border-gray-200 border-opacity-70 flex items-center justify-center text-gray-800 transition-all duration-200 hover:bg-primary hover:text-white hover:border-primary"
role="button"
>
<span className="sr-only">previous</span>
<ArrowPrev width={18} height={18} />
</div>
<div
className="next cursor-pointer absolute top-2/4 -right-4 md:-right-5 z-10 -mt-4 md:-mt-5 w-8 h-8 md:w-9 md:h-9 rounded-full bg-white shadow-xl border border-gray-200 border-opacity-70 flex items-center justify-center text-gray-800 transition-all duration-200 hover:bg-primary hover:text-white hover:border-primary"
role="button"
>
<span className="sr-only">next</span>
<ArrowNext width={18} height={18} />
</div>
</div>
</div>
);
}
FlashDealsProducts.js file
import Products from './Products.js';
import ProductCard from './ProductCard.js';
import { ArrowNext, ArrowPrev } from "#components/icons";
import SwiperCore, { Navigation } from "swiper";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/swiper-bundle.css";
const SliderBreakpoints = {
320: {
slidesPerView: 1,
spaceBetween: 0,
},
580: {
slidesPerView: 2,
spaceBetween: 16,
},
1024: {
slidesPerView: 3,
spaceBetween: 16,
},
1920: {
slidesPerView: 4,
spaceBetween: 24,
},
};
SwiperCore.use([Navigation]);
export default function FlashDealProducts() {
return (
<div className='flex mt-14 flex-col'>
<div className='flex pl-1 flex-nowrap bg-white p-4'>
<h2 className=' flex-nowrap ml-7 font-bold text-lg'> Flash Deals </h2>
<span className='text-sm ml-20 font-light text-gray-800 '> Ends in </span>
<span className='px-1 ml-4 bg-red-700 text-white font-medium'> 10 hours</span>
</div>
<div className="px-6 py-5 md:px-8 xl:px-12 md:py-10 border-t bg-white border-gray-200">
<div className="relative">
<Swiper
id="flash-deals"
loop={true}
breakpoints={SliderBreakpoints}
navigation={{
nextEl: ".next",
prevEl: ".prev",
}}
>
{Products?.map((d) => (
<SwiperSlide key={d.id}>
<ProductCard key={d.id}
title={d.title}
image={d.image}
basePrice={d.basePrice}
flashHeight={200}
flashWidth={200}
discount={d.discount}
currentPrice={d.currentPrice} />
</SwiperSlide>
))}
</Swiper>
<div
className="prev cursor-pointer absolute top-2/4 -left-4 md:-left-5 z-10 -mt-4 md:-mt-5 w-8 h-8 md:w-9 md:h-9 rounded-full bg-white shadow-xl border border-gray-200 border-opacity-70 flex items-center justify-center text-gray-800 transition-all duration-200 hover:bg-primary hover:text-white hover:border-primary"
role="button"
>
<span className="sr-only">previous</span>
<ArrowPrev width={18} height={18} />
</div>
<div
className="next cursor-pointer absolute top-2/4 -right-4 md:-right-5 z-10 -mt-4 md:-mt-5 w-8 h-8 md:w-9 md:h-9 rounded-full bg-white shadow-xl border border-gray-200 border-opacity-70 flex items-center justify-center text-gray-800 transition-all duration-200 hover:bg-primary hover:text-white hover:border-primary"
role="button"
>
<span className="sr-only">next</span>
<ArrowNext width={18} height={18} />
</div>
</div>
</div>
{/* </div> */}
</div>
)
}
Check, both values of navigation object in both files are same.
Assign different values to prevEl and nextEl property for every swiper
component you use in your project.
navigation={{
nextEl: ".next", // both should be unique in every swiper
// component
prevEl: ".prev",
}}
Either you change both values or one of them in your file only if you
are using two swiper component in your project else you have to assign
different values to navigation property in every swiper component.
Make sure to replace it with new value in classes below.