Data gotten from endpoint does not show in Picker - json
So am trying to get this into the dropdown Picker.
When i send a request to the server , i get this back as response.
{
"status": "success",
"message": "Banks fetched successfully",
"data": [
{
"id": 132,
"code": "560",
"name": "Page MFBank"
},
{
"id": 133,
"code": "304",
"name": "Stanbic Mobile Money"
},
{
"id": 134,
"code": "308",
"name": "FortisMobile"
},
{
"id": 135,
"code": "328",
"name": "TagPay"
},
{
"id": 136,
"code": "309",
"name": "FBNMobile"
},
{
"id": 137,
"code": "011",
"name": "First Bank of Nigeria"
},
{
"id": 138,
"code": "326",
"name": "Sterling Mobile"
},
{
"id": 139,
"code": "990",
"name": "Omoluabi Mortgage Bank"
},
{
"id": 140,
"code": "311",
"name": "ReadyCash (Parkway)"
},
{
"id": 141,
"code": "057",
"name": "Zenith Bank"
},
{
"id": 142,
"code": "068",
"name": "Standard Chartered Bank"
},
{
"id": 143,
"code": "306",
"name": "eTranzact"
},
{
"id": 144,
"code": "070",
"name": "Fidelity Bank"
},
{
"id": 145,
"code": "023",
"name": "CitiBank"
},
{
"id": 146,
"code": "215",
"name": "Unity Bank"
},
{
"id": 147,
"code": "323",
"name": "Access Money"
},
{
"id": 148,
"code": "302",
"name": "Eartholeum"
},
{
"id": 149,
"code": "324",
"name": "Hedonmark"
},
{
"id": 150,
"code": "325",
"name": "MoneyBox"
},
{
"id": 151,
"code": "301",
"name": "JAIZ Bank"
},
{
"id": 152,
"code": "050",
"name": "Ecobank Plc"
},
{
"id": 153,
"code": "307",
"name": "EcoMobile"
},
{
"id": 154,
"code": "318",
"name": "Fidelity Mobile"
},
{
"id": 155,
"code": "319",
"name": "TeasyMobile"
},
{
"id": 156,
"code": "999",
"name": "NIP Virtual Bank"
},
{
"id": 157,
"code": "320",
"name": "VTNetworks"
},
{
"id": 158,
"code": "221",
"name": "Stanbic IBTC Bank"
},
{
"id": 159,
"code": "501",
"name": "Fortis Microfinance Bank"
},
{
"id": 160,
"code": "329",
"name": "PayAttitude Online"
},
{
"id": 161,
"code": "322",
"name": "ZenithMobile"
},
{
"id": 162,
"code": "303",
"name": "ChamsMobile"
},
{
"id": 163,
"code": "403",
"name": "SafeTrust Mortgage Bank"
},
{
"id": 164,
"code": "551",
"name": "Covenant Microfinance Bank"
},
{
"id": 165,
"code": "415",
"name": "Imperial Homes Mortgage Bank"
},
{
"id": 166,
"code": "552",
"name": "NPF MicroFinance Bank"
},
{
"id": 167,
"code": "526",
"name": "Parralex"
},
{
"id": 168,
"code": "035",
"name": "Wema Bank"
},
{
"id": 169,
"code": "084",
"name": "Enterprise Bank"
},
{
"id": 170,
"code": "063",
"name": "Diamond Bank"
},
{
"id": 171,
"code": "305",
"name": "Paycom"
},
{
"id": 172,
"code": "100",
"name": "SunTrust Bank"
},
{
"id": 173,
"code": "317",
"name": "Cellulant"
},
{
"id": 174,
"code": "401",
"name": "ASO Savings and & Loans"
},
{
"id": 175,
"code": "030",
"name": "Heritage"
},
{
"id": 176,
"code": "402",
"name": "Jubilee Life Mortgage Bank"
},
{
"id": 177,
"code": "058",
"name": "GTBank Plc"
},
{
"id": 178,
"code": "032",
"name": "Union Bank"
},
{
"id": 179,
"code": "232",
"name": "Sterling Bank"
},
{
"id": 180,
"code": "076",
"name": "Skye Bank"
},
{
"id": 181,
"code": "082",
"name": "Keystone Bank"
},
{
"id": 182,
"code": "327",
"name": "Pagatech"
},
{
"id": 183,
"code": "559",
"name": "Coronation Merchant Bank"
},
{
"id": 184,
"code": "601",
"name": "FSDH"
},
{
"id": 185,
"code": "313",
"name": "Mkudi"
},
{
"id": 186,
"code": "214",
"name": "First City Monument Bank"
},
{
"id": 187,
"code": "314",
"name": "FET"
},
{
"id": 188,
"code": "523",
"name": "Trustbond"
},
{
"id": 189,
"code": "315",
"name": "GTMobile"
},
{
"id": 190,
"code": "033",
"name": "United Bank for Africa"
},
{
"id": 191,
"code": "044",
"name": "Access Bank"
},
{
"id": 567,
"code": "90115",
"name": "TCF MFB"
}
]
}
But when i put this in react native to get back the response i am getting very empty results, i do not know what is wrong and it is looking thus :
I got lost along the line. I do not seem to understand why and where i went wrong.
My code is looking thus :
import {
ImageBackground,
Modal,
ScrollView,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
} from 'react-native';
import {Picker} from '#react-native-picker/picker';
import React, {useEffect, useState} from 'react';
import {useNavigation} from '#react-navigation/native';
import BackgroundOpacity from './BackgroundOpacity';
const LocalPayments = ({ item }) => {
const navigation = useNavigation();
const[getBanks, setGetBanks] = useState([]);
const [bank_name, setBank_name] = useState('');
const [bank_code, setBank_code] = useState('');
const [modalVisible, setModalVisible] = useState(false);
getLocalBanks = async () => {
var url = 'https://api.flutterwave.com/v3/banks/NG';
fetch(url, {
method: 'GET',
headers: {
'Content-type': 'application/json',
'Authorization': 'Bearer FLWSECK_TEST-72fe360edef17334f4817a17407011bb-X',
},
})
.then(response => response.json())
.then(responseJson => {
setGetBanks(responseJson.data);
setBank_name(responseJson.data.name);
setBank_code(responseJson.data.code);
//setLoading(false);
});
};
useEffect(()=>{
getLocalBanks();
//console.log({getBanks})
});
showBanks = () =>{
alert({})
}
return (
<View style={styles.container}>
<BackgroundOpacity
display={Platform.OS === 'ios' ? false : modalVisible}
/>
<View style={styles.space} />
<ScrollView
contentContainerStyle={{
justifyContent: 'space-between',
alignItems: 'center',
}}>
<ImageBackground
source={{
uri: 'asset:/logo/bg.JPG',
}}
imageStyle={{borderRadius: 6}}
style={{
top: -30,
paddingTop: 95,
alignSelf: 'center',
width: 328,
height: 115,
borderadius: 9,
justifyContent: 'center',
alignSelf: 'center',
alignItems: 'center',
}}>
<View>
<Text style={styles.accText}>Wallet Balance</Text>
<Text style={styles.text}> 250,000 </Text>
</View>
</ImageBackground>
<View
style={{
borderRadius: 5,
borderWidth: 1,
overflow: 'hidden',
height: 35,
padding: 0,
borderColor: '#00BB23',
}}>
{
<Picker
selectedValue={''}
onValueChange={(itemValue, itemIndex) => this.setState({})}
style={{
width: 300,
height: 55,
borderBottomWidth: 1,
}}
itemStyle={{
fontSize: 25,
fontFamily: 'Poppins-Medium',
}}>
<Picker.Item label="Select Bank" value="accNum" /> //<-- Here the data should show in this picker
{item?.attributes.map((item, key) => (
<Picker.Item
label={bank_name}
value={bank_code}
key={item}
/>
))}
</Picker>
}
</View>
<View style={styles.space}/>
<TextInput
placeholder="Destination Account"
onChangeText={creditAccount => this.setState({creditAccount})}
style={styles.input}
/>
<TextInput
placeholder=" Amount"
onChangeText={amount => this.setState({amount})}
style={styles.input}
/>
<TextInput
placeholder=" Narration"
onChangeText={description => this.setState({description})}
style={styles.input}
/>
<View
style={{
borderRadius: 5,
borderWidth: 1,
overflow: 'hidden',
height: 35,
padding: 0,
top: 10,
borderColor: '#00BB23',
}}>
{
<Picker
style={{
width: 300,
height: 55,
borderBottomWidth: 1,
}}
itemStyle={{
fontSize: 25,
fontFamily: 'Poppins-Medium',
}}>
<Picker.Item label="Currency" value="accNum" />
<Picker.Item label="NGN" value="NGN" />
</Picker>
}
</View>
<TouchableOpacity
onPress={() => {
setModalVisible(true);
}}
style={styles.button}>
<Text style={styles.loginbtn}> Transfer </Text>
</TouchableOpacity>
<Modal
hasBackdrop={true}
backdropOpacity={0.2}
backdropColor="black"
transparent
visible={modalVisible}
onRequestClose={() => setModalVisible(false)}>
<View style={styles.modal}>
<Text>Hello From Modal</Text>
<TouchableOpacity>
<Text>Modal! Modal!</Text>
</TouchableOpacity>
</View>
</Modal>
</ScrollView>
</View>
);
};
export default LocalPayments;
const styles = StyleSheet.create({
container: {
paddingTop: 40,
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
},
modal: {
top: '50%',
height: '50%',
backgroundColor: '#fff',
},
accText: {
top: -50,
paddingTop: 10,
justifyContent: 'center',
alignItems: 'center',
fontFamily: 'Poppins-Medium',
fontSize: 12,
color: 'white',
textAlign: 'center',
},
text: {
top: -50,
fontSize: 20,
color: 'white',
textAlign: 'center',
fontFamily: 'Poppins-Bold',
},
input: {
top: 10,
width: 300,
height: 55,
margin: 10,
fontSize: 12,
borderColor: '#00BB23',
fontFamily: 'Poppins-Bold',
borderRadius: 5,
borderWidth: 1,
marginBottom: 30,
},
button: {
marginTop: 40,
width: 150,
height: 50,
padding: 10,
borderRadius: 10,
backgroundColor: '#00BB23',
alignItems: 'center',
},
Regbutton: {
width: 150,
height: 52,
padding: 10,
borderRadius: 10,
backgroundColor: '#ffffff',
alignItems: 'center',
borderWidth: 2,
borderColor: '#030303',
},
loginbtn: {
color: '#ffff',
fontSize: 15,
fontFamily: 'Poppins-Medium',
},
AccountBalance: {
fontSize: 13,
fontWeight: 'bold',
textAlign: 'left',
},
loginbtn2: {
color: '#030303',
fontSize: 20,
fontWeight: 'bold',
},
logo: {
width: 150,
height: 150,
},
space: {
top: 10,
width: 10,
height: 20,
},
space2: {
width: 10,
height: 10,
},
imageStyle: {
flexDirection: 'row',
justifyContent: 'center',
padding: 5,
margin: 2,
height: 15,
width: 15,
resizeMode: 'stretch',
marginBottom: 8,
marginTop: 8,
alignItems: 'center',
},
});
Sought the internet and i could not find something tangible. Please help.
Edit
So it gets it, but once the page loads up, it just flashes the banks,i want it to get the data into a drop down, then , from there i can select the drop down and it shows all the banks
See how the screen looks.
Source code looks thus :
import {
ImageBackground,
Modal,
ScrollView,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
} from 'react-native';
import {Picker} from '#react-native-picker/picker';
import React, {useEffect, useState} from 'react';
import {useNavigation} from '#react-navigation/native';
import BackgroundOpacity from './BackgroundOpacity';
const LocalPayments = ({item}) => {
const navigation = useNavigation();
const [getBanks, setGetBanks] = useState([]);
const [bank_name, setBank_name] = useState('');
const [bank_code, setBank_code] = useState('');
const [modalVisible, setModalVisible] = useState(false);
getLocalBanks = async () => {
var url = 'https://api.flutterwave.com/v3/banks/NG';
fetch(url, {
method: 'GET',
headers: {
'Content-type': 'application/json',
Authorization: 'Bearer FLWSECK_TEST-72fe360edef17334f4817a17407011bb-X',
},
})
.then(response => response.json())
.then(responseJson => {
setGetBanks(responseJson.data);
setBank_name(responseJson.data.name);
setBank_code(responseJson.data.code);
//setLoading(false);
});
};
useEffect(() => {
getLocalBanks();
//console.log({getBanks})
});
showBanks = () => {
alert({});
};
return (
<View style={styles.container}>
<BackgroundOpacity
display={Platform.OS === 'ios' ? false : modalVisible}
/>
<View style={styles.space} />
<ScrollView
contentContainerStyle={{
justifyContent: 'space-between',
alignItems: 'center',
}}>
<ImageBackground
source={{
uri: 'asset:/logo/bg.JPG',
}}
imageStyle={{borderRadius: 6}}
style={{
top: -30,
paddingTop: 95,
alignSelf: 'center',
width: 328,
height: 115,
borderadius: 9,
justifyContent: 'center',
alignSelf: 'center',
alignItems: 'center',
}}>
<View>
<Text style={styles.accText}>Wallet Balance</Text>
<Text style={styles.text}> 250,000 </Text>
</View>
</ImageBackground>
<View
style={{
borderRadius: 5,
borderWidth: 1,
overflow: 'hidden',
height: 35,
padding: 0,
borderColor: '#00BB23',
}}>
{
<Picker
selectedValue={''}
onValueChange={(itemValue, itemIndex) => this.setState({})}
style={{
width: 300,
height: 55,
borderBottomWidth: 1,
}}
itemStyle={{
fontSize: 25,
fontFamily: 'Poppins-Medium',
}}>
<Picker.Item label="Select Bank" value="accNum" />
{getBanks.map((bank, index) => (
<Picker.Item label={bank.name} value={bank.code} key={index} />
))}
</Picker>
}
</View>
<View style={styles.space} />
<TextInput
placeholder="Destination Account"
onChangeText={creditAccount => this.setState({creditAccount})}
style={styles.input}
/>
<TextInput
placeholder=" Amount"
onChangeText={amount => this.setState({amount})}
style={styles.input}
/>
<TextInput
placeholder=" Narration"
onChangeText={description => this.setState({description})}
style={styles.input}
/>
<View
style={{
borderRadius: 5,
borderWidth: 1,
overflow: 'hidden',
height: 35,
padding: 0,
top: 10,
borderColor: '#00BB23',
}}>
{
<Picker
style={{
width: 300,
height: 55,
borderBottomWidth: 1,
}}
itemStyle={{
fontSize: 25,
fontFamily: 'Poppins-Medium',
}}>
<Picker.Item label="Currency" value="accNum" />
<Picker.Item label="NGN" value="NGN" />
</Picker>
}
</View>
<TouchableOpacity
onPress={() => {
setModalVisible(true);
}}
style={styles.button}>
<Text style={styles.loginbtn}> Transfer </Text>
</TouchableOpacity>
<Modal
hasBackdrop={true}
backdropOpacity={0.2}
backdropColor="black"
transparent
visible={modalVisible}
onRequestClose={() => setModalVisible(false)}>
<View style={styles.modal}>
<Text>Hello From Modal</Text>
<TouchableOpacity>
<Text>Modal! Modal!</Text>
</TouchableOpacity>
</View>
</Modal>
</ScrollView>
</View>
);
};
export default LocalPayments;
const styles = StyleSheet.create({
container: {
paddingTop: 40,
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
},
modal: {
top: '50%',
height: '50%',
backgroundColor: '#fff',
},
accText: {
top: -50,
paddingTop: 10,
justifyContent: 'center',
alignItems: 'center',
fontFamily: 'Poppins-Medium',
fontSize: 12,
color: 'white',
textAlign: 'center',
},
text: {
top: -50,
fontSize: 20,
color: 'white',
textAlign: 'center',
fontFamily: 'Poppins-Bold',
},
input: {
top: 10,
width: 300,
height: 55,
margin: 10,
fontSize: 12,
borderColor: '#00BB23',
fontFamily: 'Poppins-Bold',
borderRadius: 5,
borderWidth: 1,
marginBottom: 30,
},
button: {
marginTop: 40,
width: 150,
height: 50,
padding: 10,
borderRadius: 10,
backgroundColor: '#00BB23',
alignItems: 'center',
},
Regbutton: {
width: 150,
height: 52,
padding: 10,
borderRadius: 10,
backgroundColor: '#ffffff',
alignItems: 'center',
borderWidth: 2,
borderColor: '#030303',
},
loginbtn: {
color: '#ffff',
fontSize: 15,
fontFamily: 'Poppins-Medium',
},
AccountBalance: {
fontSize: 13,
fontWeight: 'bold',
textAlign: 'left',
},
loginbtn2: {
color: '#030303',
fontSize: 20,
fontWeight: 'bold',
},
logo: {
width: 150,
height: 150,
},
space: {
top: 10,
width: 10,
height: 20,
},
space2: {
width: 10,
height: 10,
},
imageStyle: {
flexDirection: 'row',
justifyContent: 'center',
padding: 5,
margin: 2,
height: 15,
width: 15,
resizeMode: 'stretch',
marginBottom: 8,
marginTop: 8,
alignItems: 'center',
},
});
You overlook something. Try like this please.
{getBanks.map((bank, index) => (
<Picker.Item
label={bank.name}
value={bank.code}
key={index}
/>
))}
UPDATE
Define a state variable to track the selected bank
const [selectedBank, setSelectedBank] = useState();
Modify your Picker element like that
<Picker
selectedValue={selectedBank}
onValueChange={(value, index) => setSelectedBank(value)}>
{getBanks.map((bank, index) => (
<Picker.Item
label={bank.name}
value={bank.code}
key={index}
/>
))}
</Picker>
Related
Why does my stretch attribute in mui flexbox not do anything?
So I want the boxes I have displayed in a parent box to completely stretch out. I followed the documentation on MUI for the flexbox, though after editing it a bit I do not understand why it does not work anymore :? I have given the inner items a minimum for width and height, but even without this the items do not stretch. Does the stretch attribute not mean that the parent container will be completely filled out? Here's my code: import "./styles.css"; import React from "react"; import Box, { BoxProps } from "#mui/material/Box"; import PropTypes from "prop-types"; function Item(props) { const { sx, ...other } = props; return ( <Box sx={{ border: "1px solid pink", borderRadius: 2, fontSize: "0.875rem", minHeight: "5rem", minWidth: "5rem", ...sx }} {...other} /> ); } Item.propTypes = { sx: PropTypes.oneOfType([ PropTypes.arrayOf( PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool]) ), PropTypes.func, PropTypes.object ]) }; export default function App() { const items = [ { title: "Car", color: "yellow" }, { title: "Plane", color: "lightblue" }, { title: "Bicycle", color: "lightgreen" }, { title: "Train", color: "orange" } ]; const movies = [ { title: "Seven", color: "red" }, { title: "Memento", color: "white" }, { title: "Vivarium", color: "lightgreen" }, { title: "Blue Velvet", color: "lightblue" } ]; return ( <> <Box className="Container Of Sub" style={{ backgroundColor: "lightpink", display: "flex", alignItems: "center", width: "100%", height: "100%" }} > <Box className="FirstSub" style={{ width: "50%" }}> <Box className="Header" style={{ borderRadius: "10px", paddingLeft: "10px", boxShadow: "4px 4px 20px 0px rgba(0,0,0,0.25", backgroundColor: "white" }} > <h4>Subcategory 1</h4> </Box> <Box className="Category Holder" sx={{ display: "flex", flexWrap: "wrap", alignContent: "stretch", borderRadius: 1 }} > {items.map((item) => ( <Item sx={{ backgroundColor: item.color }} > {item.title} </Item> ))} </Box> </Box> <Box className="2ndSubCategory" style={{ width: "50%", marginLeft: "20px" }} > <Box className="Header" style={{ borderRadius: "10px", paddingLeft: "10px", boxShadow: "4px 4px 20px 0px rgba(0,0,0,0.25", backgroundColor: "white" }} > <h4>Subcategory 2</h4> </Box> <Box className="Category Holder" sx={{ display: "flex", flexWrap: "wrap", alignContent: "stretch", borderRadius: 1 }} > {movies.map((item) => ( <Item sx={{ backgroundColor: item.color }} > {item.title} </Item> ))} </Box> </Box> </Box> </> ); }
How to mute remote user in Agora UI kit?
I am using AgoraUIKit from "agora-react-uikit". it is supposed to have the option to mute remote users as per their documentation, but it is not there as they showed in their demo example. Here is the github link for controls panal which is supposed to be there by default. https://github.com/AgoraIO-Community/VideoUIKit-Web-React/wiki/Guide#controls Here is a code of the App.tsx file import React, { CSSProperties, useState } from 'react' import AgoraUIKit, { layout, VideoPlaceholderProps, BtnTemplate } from 'agora-react-uikit' import 'agora-react-uikit/dist/index.css' const PageComponent: React.FunctionComponent<VideoPlaceholderProps> = ({isShown=true, showButtons=true, showSwap=false}) => { return ( <> {showButtons}{isShown}{showSwap} {BtnTemplate} </> ); }; const App: React.FunctionComponent = () => { const [videocall, setVideocall] = useState(false) const [isHost, setHost] = useState(true) const [isPinned, setPinned] = useState(false) const [username, setUsername] = useState('') return ( <div style={styles.container}> <div style={styles.videoContainer}> {videocall ? ( <> <div style={styles.nav2}> <h3 style={styles.heading}>Online Video Call</h3> <p style={styles.btn} onClick={() => setPinned(!isPinned)}> Change Layout </p> </div> <AgoraUIKit rtcProps={{ appId: 'appid', channel: 'channel name', uid: 0, token: 'token', // add your token if using app in secured mode role: isHost ? 'host' : 'audience', layout: isPinned ? layout.pin : layout.grid, activeSpeaker: true, disableRtm: false, enableScreensharing: true, CustomVideoPlaceholder: PageComponent, }} rtmProps={{ username: username || 'user', displayUsername: true, showPopUpBeforeRemoteMute: true }} callbacks={{ EndCall: () => setVideocall(false) }} styleProps={{ localBtnContainer: { backgroundColor: 'white', justifyContent: 'center', gap: "20px" }, > BtnTemplateStyles: { borderColor: 'rgb(107 107 107)' }, }} /> </> ) : ( <div style={styles.nav}> <input style={styles.input} placeholder='nickname' type='text' value={username} onChange={(e) => { setUsername(e.target.value) }} /> <h3 style={styles.btn} onClick={() => setVideocall(true)}> Start Call </h3> </div> )} </div> </div> ) } const styles = { container: { maxWidth: '1100px', margin: "0 auto", height: '100vh', display: 'flex', flex: 1, }, container2: { padding: "2px 16px" }, heading: { textAlign: 'center' as const, marginBottom: 0 }, videoContainer: { display: 'flex', flexDirection: 'column', flex: 1 } as CSSProperties, nav: { display: 'flex', justifyContent: 'space-between' }, nav2: { display: 'flex', justifyContent: 'space-between', borderBottom: "1px solid black" }, card: { // position:"absolute", // left:"0", // bottom:"0", // transform:"translate(155px, -82px)", // boxShadow: '0 4px 8px 0 rgba(0,0,0,0.2)', // transition: '0.3s', // display: 'flex', // width:"80vw", // height:"80vh", // flexDirection: "column", // justifyContent: "space-between" } as CSSProperties, btn: { backgroundColor: '#007bff', cursor: 'pointer', borderRadius: 5, padding: '4px 8px', color: '#ffffff', fontSize: 20 }, input: { display: 'flex', height: 24, alignSelf: 'center' } as CSSProperties } export default Apptype here
Inconsistent margins/spacing with Material UI Accordion
I'm using Material UI Accordion for creating a filter menu. It looks like this on some devices whereas it looks likes this on other devices with different dimensions even though the margins between the items are the same and uses the same code. On resizing the dimensions of the screen, the inconsistency changes. How to fix this inconsistency with the spacing between each filter item? Here's my file FilterAccordion.tsx: <Box className={classes.accordionRoot}> <Accordion style={{ boxShadow: "none" }} defaultExpanded={true}> <AccordionSummary expandIcon={<ExpandMore style={{ fill: "#d3d3d3" }} />}> <div className={classes.verticalrootcontainer}> <Icon onClick={(e) => e.stopPropagation()} style={{ fill: "#d3d3d3", width: "2rem", marginRight: "1rem", transform: "scale(3)", zIndex: -1, }} /> <Typography variant="body1" className={`titleAquire ${classes.title}`}> {title} </Typography> </div> </AccordionSummary> <AccordionDetails> <div className={classes.listRoot}> {Object.keys(groupByPacks).map((item, index) => { let checked = isChecked(item); return ( <div key={index} className={`${classes.list} ${ checked ? classes.selected : "" }`} onClick={() => handleOnCheck(item)}> <Typography variant="body1" className={classes.item}> {item} </Typography> <Typography variant="body1" className={classes.item}> {groupByFilteredPacks[item] ? groupByFilteredPacks[item]?.length : 0} </Typography> </div> ); })} </div> </AccordionDetails> </Accordion> </Box> And the CSS file: accordionRoot: { "& .MuiAccordion-root": { background: "transparent", }, "& .MuiAccordionDetails-root": { padding: "0px", }, "& .MuiAccordionSummary-root": { padding: "0px", marginBottom: "-1rem", }, "& .MuiCollapse-entered": { marginTop: "1rem", }, }, title: { fontSize: "18px", color: theme.on.dark, }, verticalrootcontainer: { display: "flex", alignItems: "center", }, list: { display: "flex", width: "100%", alignItems: "center", justifyContent: "space-between", marginTop: "0.2rem", padding: "0.2rem 0.5rem", cursor: "pointer", "&:first-child": { marginTop: 0, }, }, item: { textTransform: "uppercase", color: theme.on.dark, opacity: "30%", }, selected: { background: theme.on.dark, "& p": { color: theme.darkMode.light, opacity: "100%", }, }, listRoot: { width: "100%", },
How to format adaptive cards like the old version of webchat
The new version of the standard webchat channel ("gemini") stripped out all of the formatting. I was able to replicate most of the old interface via tweaks in the botframework-webchat implementation, but I cannot get the adaptive card formatting to match. With the general formatting I was able to get it close, and the adaptiveCardHostConfig tweaks shown here on Github got a bit closer, but I still can't figure out how to replicate it. Specifically, the chat bubble (which is gray in my implementation) no longer appears behind the adaptive card. This is especially noticeable for carousels, where it used to be one "bubble" with multiple cards and is now discrete cards. Furthermore, the buttons are no longer interactive (blue border used to appear on mouseover), and the bublle "nub" is absent. Please see below for examples. Note that I DO know how to make the background for the card itself gray to match the bubbles, but that is not the look that I want or that displayed previously. In summary, I'm asking How can I format the gray background like was present in the previous version. How can I add the bubble nub to the card (or perhaps more accurately, make the card appear inside a bubble). How can I make the buttons on the adaptive card interactive Single Card (new on left, old on right) Carousel (new on left, old on right) And here is the website code <!DOCTYPE html> <html> <head> <title>Support Bot</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script> <style> html, body { height: 100%; } body { margin: 0; } html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; } #chatbotTitle { display: flex; align-items: center; height: 40px; width: 100%; background-color: #0067CC; color: #FFFFFF; font-family: Calibri, Helvetica Neue, Arial, sans-serif; justify-content: space-between; } #webchat { height: calc(100% - 40px); width: 100%; } .btn { display: flex; background-color: white; border: 1px solid #767676; color: #0067CC; text-align: center; margin: 15px; } .btn:hover { border-color: #444444; } .btn:active { background-color: #CCCCCC; } </style> </head> <body> <div id="chatbotTitle"><h3 style="padding-left:10px;">Support Bot</h3><button class="btn" id="transcriptButton">Email Transcript</button></div> <div id="webchat" role="main"></div> <script> let interval; var PageTitleNotification = { Vars:{ OriginalTitle: document.title, Interval: null }, On: function(notification, intervalSpeed){ var _this = this; _this.Vars.Interval = setInterval(function(){ document.title = (_this.Vars.OriginalTitle == document.title) ? notification : _this.Vars.OriginalTitle; }, (intervalSpeed) ? intervalSpeed : 1000); }, Off: function(){ clearInterval(this.Vars.Interval); document.title = this.Vars.OriginalTitle; } } // We are using a customized store to add hooks to connect event const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => { if (action.type === 'WEB_CHAT/SEND_MESSAGE') { // Message sent by the user PageTitleNotification.Off(); clearTimeout(interval); } else if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY' && action.payload.activity.name !== "inactive") { // Message sent by the bot clearInterval(interval); interval = setTimeout(() => { // Change title to flash the page PageTitleNotification.On('Are you still there?'); // Notify bot the user has been inactive dispatch({ type: 'WEB_CHAT/SEND_EVENT', payload: { name: 'inactive', value: '' } }); }, 300000) } return next(action); }); const adaptiveCardHostConfig = { "spacing": { "small": 3, "default": 8, "medium": 20, "large": 30, "extraLarge": 40, "padding": 10 }, "separator": { "lineThickness": 1, "lineColor": "#EEEEEE" }, "supportsInteractivity": true, "fontTypes": { "default": { "fontFamily": "Calibri, sans-serif", "fontSizes": { "small": 12, "default": 14, "medium": 17, "large": 21, "extraLarge": 26 }, "fontWeights": { "lighter": 200, "default": 400, "bolder": 600 } }, "monospace": { "fontFamily": "'Courier New', Courier, monospace", "fontSizes": { "small": 12, "default": 14, "medium": 17, "large": 21, "extraLarge": 26 }, "fontWeights": { "lighter": 200, "default": 400, "bolder": 600 } } }, "containerStyles": { "default": { "backgroundColor": "#FFFFFF", "foregroundColors": { "default": { "default": "#000000", "subtle": "#767676" }, "accent": { "default": "#0063B1", "subtle": "#0063B1" }, "attention": { "default": "#FF0000", "subtle": "#DDFF0000" }, "good": { "default": "#54a254", "subtle": "#DD54a254" }, "warning": { "default": "#c3ab23", "subtle": "#DDc3ab23" } } }, "emphasis": { "backgroundColor": "#F0F0F0", "foregroundColors": { "default": { "default": "#000000", "subtle": "#767676" }, "accent": { "default": "#2E89FC", "subtle": "#882E89FC" }, "attention": { "default": "#FF0000", "subtle": "#DDFF0000" }, "good": { "default": "#54a254", "subtle": "#DD54a254" }, "warning": { "default": "#c3ab23", "subtle": "#DDc3ab23" } } }, "accent": { "backgroundColor": "#C7DEF9", "foregroundColors": { "default": { "default": "#333333", "subtle": "#EE333333" }, "dark": { "default": "#000000", "subtle": "#66000000" }, "light": { "default": "#FFFFFF", "subtle": "#33000000" }, "accent": { "default": "#2E89FC", "subtle": "#882E89FC" }, "attention": { "default": "#cc3300", "subtle": "#DDcc3300" }, "good": { "default": "#54a254", "subtle": "#DD54a254" }, "warning": { "default": "#e69500", "subtle": "#DDe69500" } } }, "good": { "backgroundColor": "#CCFFCC", "foregroundColors": { "default": { "default": "#333333", "subtle": "#EE333333" }, "dark": { "default": "#000000", "subtle": "#66000000" }, "light": { "default": "#FFFFFF", "subtle": "#33000000" }, "accent": { "default": "#2E89FC", "subtle": "#882E89FC" }, "attention": { "default": "#cc3300", "subtle": "#DDcc3300" }, "good": { "default": "#54a254", "subtle": "#DD54a254" }, "warning": { "default": "#e69500", "subtle": "#DDe69500" } } }, "attention": { "backgroundColor": "#FFC5B2", "foregroundColors": { "default": { "default": "#333333", "subtle": "#EE333333" }, "dark": { "default": "#000000", "subtle": "#66000000" }, "light": { "default": "#FFFFFF", "subtle": "#33000000" }, "accent": { "default": "#2E89FC", "subtle": "#882E89FC" }, "attention": { "default": "#cc3300", "subtle": "#DDcc3300" }, "good": { "default": "#54a254", "subtle": "#DD54a254" }, "warning": { "default": "#e69500", "subtle": "#DDe69500" } } }, "warning": { "backgroundColor": "#FFE2B2", "foregroundColors": { "default": { "default": "#333333", "subtle": "#EE333333" }, "dark": { "default": "#000000", "subtle": "#66000000" }, "light": { "default": "#FFFFFF", "subtle": "#33000000" }, "accent": { "default": "#2E89FC", "subtle": "#882E89FC" }, "attention": { "default": "#cc3300", "subtle": "#DDcc3300" }, "good": { "default": "#54a254", "subtle": "#DD54a254" }, "warning": { "default": "#e69500", "subtle": "#DDe69500" } } } }, "imageSizes": { "small": 40, "medium": 80, "large": 160 }, "actions": { "maxActions": 100, "spacing": "default", "buttonSpacing": 8, "showCard": { "actionMode": "inline", "inlineTopMargin": 8 }, "actionsOrientation": "vertical", "actionAlignment": "stretch" }, "adaptiveCard": { "allowCustomStyle": false }, "imageSet": { "imageSize": "medium", "maxImageHeight": 100 }, "factSet": { "title": { "color": "default", "size": "default", "isSubtle": false, "weight": "bolder", "wrap": true, "maxWidth": 150 }, "value": { "color": "default", "size": "default", "isSubtle": false, "weight": "default", "wrap": true }, "spacing": 8 } }; window.WebChat.renderWebChat( { adaptiveCardHostConfig, directLine: window.WebChat.createDirectLine({ token: 'MYTOKENHERE' }), store: store, userID: 'userID', username: 'userName', locale: 'en-US', styleOptions: { botAvatarInitials: 'BOT', userAvatarInitials: 'USR', accent: '#0067CC', backgroundColor: 'White', cardEmphasisBackgroundColor: '#F0F0F0', paddingRegular: 10, paddingWide: 10 * 2, messageActivityWordBreak: 'break-word', fontSizeSmall: '80%', avatarSize: 40, botAvatarBackgroundColor: '#0067CC', botAvatarImage: '', botAvatarInitials: '', userAvatarBackgroundColor: '#ECEFF1', userAvatarImage: '', userAvatarInitials: '', bubbleBackground: '#ECEFF1', bubbleBorderColor: '#E6E6E6', bubbleBorderRadius: 8, bubbleBorderStyle: 'solid', bubbleBorderWidth: 1, bubbleFromUserBackground: '#0067CC', bubbleFromUserBorderColor: '#E6E6E6', bubbleFromUserBorderRadius: 8, bubbleFromUserBorderStyle: 'solid', bubbleFromUserBorderWidth: 1, bubbleFromUserNubOffset: 'bottom', bubbleFromUserNubSize: 10, bubbleFromUserTextColor: 'White', bubbleImageHeight: 240, bubbleMaxWidth: 480, bubbleMinHeight: 30, bubbleMinWidth: 250, bubbleNubOffset: 'bottom', bubbleNubSize: 10, bubbleTextColor: 'Black', markdownRespectCRLF: true, richCardWrapTitle: false, rootHeight: '100%', rootWidth: '100%', hideScrollToEndButton: false, hideSendBox: false, hideUploadButton: true, microphoneButtonColorOnDictate: '#F33', sendBoxBackground: 'White', sendBoxButtonColor: '#767676', sendBoxButtonColorOnDisabled: '#CCC', sendBoxButtonColorOnFocus: '#0067CC', sendBoxButtonColorOnHover: '#0067CC', sendBoxDisabledTextColor: '#767676', // defaults to subtle sendBoxHeight: 40, sendBoxMaxHeight: 200, sendBoxTextColor: 'Black', sendBoxBorderBottom: 'solid 5px #DBDEE1', sendBoxBorderLeft: 'solid 5px #DBDEE1', sendBoxBorderRight: 'solid 5px #DBDEE1', sendBoxBorderTop: 'solid 5px #DBDEE1', sendBoxPlaceholderColor: undefined, // defaults to subtle sendBoxTextWrap: false, showSpokenText: false, suggestedActionBackground: 'White', suggestedActionBorder: undefined, suggestedActionBorderColor: '#CCCCCC', suggestedActionBorderRadius: 0, suggestedActionBorderStyle: 'solid', suggestedActionBorderWidth: 1, suggestedActionDisabledBackground: '#F9F9F9', suggestedActionDisabledBorder: null, suggestedActionDisabledBorderColor: '#E6E6E6', suggestedActionDisabledBorderStyle: 'solid', suggestedActionDisabledBorderWidth: 1, suggestedActionDisabledTextColor: '#767676', suggestedActionHeight: 30, suggestedActionImageHeight: 20, suggestedActionLayout: 'carousel', suggestedActionTextColor: null, groupTimestamp: false, sendTimeout: 20000, sendTimeoutForAttachments: 120000, timestampColor: '#767676', timestampFormat: 'relative', transcriptOverlayButtonBackground: 'rgba(0, 0, 0, .6)', transcriptOverlayButtonBackgroundOnFocus: 'rgba(0, 0, 0, .8)', transcriptOverlayButtonBackgroundOnHover: 'rgba(0, 0, 0, .8)', transcriptOverlayButtonColor: 'White', transcriptOverlayButtonColorOnFocus: 'White', transcriptOverlayButtonColorOnHover: 'White', typingAnimationBackgroundImage: null, typingAnimationDuration: 5000, typingAnimationHeight: 20, typingAnimationWidth: 64, subtle: '#767676' } }, document.getElementById('webchat') ); document.querySelector('#transcriptButton').addEventListener('click', () => { store.dispatch({ type: 'WEB_CHAT/SEND_MESSAGE', payload: { text: 'Email me a transcript' } }); }); </script> </body> </html>
Web Chat and Adaptive Cards are both open source, so it's a good idea to download their source code if you want to figure out how they work. In the Web Chat repo you can switch to the v3 branch to see how v3 works. Web Chat uses the Adaptive Cards JavaScript SDK, and the code that handles parsing and rendering is in card-elements.ts. In botchat.css, you can see the styles that create the background you want here: .wc-message-content { border-radius: 2px; box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); padding: 8px; word-break: break-word; } .wc-message-from-bot .wc-message-content { background-color: #eceff1; color: #000000; } Those classes aren't used in Web Chat v4, but you can apply it to your attachments and carousels like this: div.attachment.bubble, div.content > ul.webchat__carousel__item_indented { background-color: #eceff1; color: #000000; border-radius: 2px; box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); padding: 8px; } I'm being pretty specific with the selector because there's another style that will try to set the padding to 0. You can just use the !important keyword if you want. You've already seen that Web Chat doesn't allow bubble nubs on attachments in v4. The line responsible for this is here: <Bubble className="attachment bubble" fromUser={fromUser} key={index} nub={false}> You can modify the way activities are rendered using activity middleware according to this sample. In your case you'll want to render an SVG element alongside the activity. To add hover styles to your buttons, you can again have a look at botchat.css: .wc-card button:hover { background-color: transparent; border-color: #0078d7; color: #0078d7; } You can use all three of those declarations or just border-color: .ac-adaptiveCard button:hover { border-color: #0078d7; }
React Native - Element type is invalid: Expected a string
I'm wanting to display a static map inside my app based off some coords. I am using the following library: react-native-google-static-map I have done the following: npm install --save react-native-google-static-map And added the following into my view: var GoogleStaticMap = require('react-google-static-map'); And <GoogleStaticMap style={styles.map} latitude={'32.064171'} longitude={'34.7748068'} zoom={13} size={{ width: 300, height: 550 }} This builds fine. However when I go and into the view, I get the following error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method ofSingle. Where Single is the class name for my view. Any ideas to where I am going wrong here? Full code: import React, { Component } from 'react'; import { View } from 'react-native'; import { AppRegistry, StyleSheet, Text, TextInput, TouchableHighlight, ActivityIndicator, NavigatorIOS, ListView, Image, WebView, } from 'react-native'; var GoogleStaticMap = require('react-google-static-map'); class Single extends Component { render() { return ( <Image style={styles.container} source={require('../../images/home.jpg')}> <View style={styles.map}> <GoogleStaticMap style={styles.map} latitude={'32.064171'} longitude={'34.7748068'} zoom={13} size={{ width: 300, height: 550 }} /> <View style={styles.business}> <Text style={styles.businessName}>{this.props.property.street_address} {this.props.property.postcode}</Text> </View> <View style={styles.overview}> <Text style={styles.heading}> Overview </Text> <Text style={styles.bodyText}>{this.props.property.overview}</Text> </View> <View style={styles.overview}> <Text style={styles.heading}> Opening Hours </Text> <Text style={styles.bodyText}>Monday {this.props.property.opening_hours.monday_open} - {this.props.property.opening_hours.monday_close}</Text> <Text style={styles.bodyText}>Tuesday {this.props.property.opening_hours.monday_open} - {this.props.property.opening_hours.monday_close}</Text> <Text style={styles.bodyText}>Wednesday {this.props.property.opening_hours.monday_open} - {this.props.property.opening_hours.monday_close}</Text> <Text style={styles.bodyText}>Thursday {this.props.property.opening_hours.monday_open} - {this.props.property.opening_hours.monday_close}</Text> <Text style={styles.bodyText}>Friday {this.props.property.opening_hours.monday_open} - {this.props.property.opening_hours.monday_close}</Text> <Text style={styles.bodyText}>Saturday {this.props.property.opening_hours.monday_open} - {this.props.property.opening_hours.monday_close}</Text> <Text style={styles.bodyText}>Sunday {this.props.property.opening_hours.monday_open} - {this.props.property.opening_hours.monday_close}</Text> </View> </View> </Image> ) } } const styles = StyleSheet.create({ business: { backgroundColor: 'rgba(0,0,0,0.5)', marginTop: 10, }, businessName: { fontSize: 14, padding:10, color: '#ffffff' }, map: { flex: 1, marginTop: 30, width: null, height:10, }, overview: { marginTop: 30, left:0, height:null, backgroundColor: 'rgba(0,0,0,0.5)', }, bodyText: { color: '#ffffff', padding: 10, }, heading: { padding:5, backgroundColor: '#008983', color: '#ffffff' }, container: { flex: 1, marginTop: 50, width:null, height:null, }, backdropView: { top:100, height: 200, width: 320, backgroundColor: 'rgba(0,0,0,0.5)', }, headline: { fontSize: 20, textAlign: 'center', padding:40, backgroundColor: 'rgba(0,0,0,0)', color: 'white' }, backdropViewTitle: { color: 'white', textAlign: 'center', padding:10, fontSize: 20, }, search: { height:50, fontSize: 15, borderWidth: 1, borderColor: '#fff', borderRadius: 1, color: '#fff', width:295, marginTop:10, marginLeft:10, padding:10 }, content:{ backgroundColor:'#ebeef0', flex:1, alignItems:'center' //<----- }, messageBoxTitleText:{ fontWeight:'bold', color:'#fff', textAlign:'center', fontSize:20, marginBottom:10 }, messageBoxBodyText:{ color:'#fff', fontSize:16 }, logo: { top:50, }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, }, instructions: { textAlign: 'center', color: '#333333', marginBottom: 5, }, flowRight: { flexDirection: 'row', alignItems: 'center', width: 300, left:60 }, buttonText: { fontSize: 18, color: 'white', alignSelf: 'center' }, button: { top:10, left:10, height: 40, width:100, flexDirection: 'row', backgroundColor: '#48BBEC', borderColor: '#48BBEC', marginBottom: 10, alignSelf: 'stretch', justifyContent: 'center' }, searchLocation: { height: 36, padding: 4, marginRight: 5, flex: 5, fontSize: 10, borderWidth: 1, borderColor: '#48BBEC', borderRadius: 8, color: '#48BBEC', }, searchInput: { height: 36, padding: 4, marginRight: 5, flex: 4, fontSize: 10, borderWidth: 1, borderColor: '#48BBEC', borderRadius: 8, color: '#48BBEC' }, }); module.exports = Single;
You need to do one of the following. Import GoogleStaticMap by using either: var GoogleStaticMap = require('react-native-google-static-map').default; or import GoogleStaticMap from 'react-native-google-static-map';