Close accordions on radio button click

Viewed 474

I have an accordion component in my React Native app which is from galio framework . I have populated it with api data. The accordion closes if you click in the title but I want it to close when I select a radio button. Here is my code:

const Step3 = () => {
  const [questions, setQuestions] = useState([]);
  const [answers, setAnswers] = useState([]);
  const [icon, setIcons] = useState([]);
  const [iconColor, setIconsColor] = useState([])
  const [refreshing, setRefreshing] = useState(true);

  const getQuestions = async () => {
    const locale = i18next.language; // TODO: get current locale
    const response = await apiStandarts.get(`/questions?locale=${locale}`, {
      params: { active: 1, _sortId: [1,2] , _sort: "sortId:ASC"},
    });
    setRefreshing(false)
    setQuestions(response.data);
  };
  const isOptionSelected = (option) => {
    const answer = answers[option.question];
    if (answer) {
      return option.id == answer.id;
    }
    return false;
  };

  const questionIcon = async () => {
    const response = await apiStandarts.get(`/commitments-icons`);
    setIcons(response.data)
  }

  const questionIconColor = async () => {
    const response = await apiStandarts.get(`/commitments`);
    setIconsColor(response.data)
  }


  const objectMap = (obj, fn) =>
    Object.fromEntries(
      Object.entries(obj).map(([k, v], i) => [k, fn(v, k, i)])
    );
  const newAnswers = objectMap(answers, (item) => {
    return [item.id, item.description];
  });

  // useEffect(() => {
  //   questionIcon();
  // }, []);
  useEffect(() => {
    questionIcon();
    getQuestions();
  }, []);

  const OptionList = (groupOption) => {
    return (
      groupOption.options.map((item, index) => {
        const clickedRadio = () => {
          const selectedOption = { [item.question]: { ...item } };
          setAnswers({ ...answers, ...selectedOption });
        };
        let status = isOptionSelected(item) ? true : false;
        return (

          <Radio
          initialValue={status}
          label={item.description}
          onChange={() => clickedRadio()}
          color="rgba(0,0,0,.54)"
          radioInnerStyle={{backgroundColor: "#3671a6"}}
          labelStyle={ styles.label}
          containerStyle={{ width: 300, padding: 5 }}
        />
        );
      })
    );
  };




  return (
    <View style={styles.container}>
      <Text style={{ fontWeight: "bold", fontSize: 12, color: "#6B24" }}>
        {t("Choose an option/Scroll for more questions")}
      </Text>

      <FlatList
        data={questions}
        keyExtractor={(result) => result.id.toString()}
        contentContainerStyle={{ padding: 5, paddingBottom: 5 }}
        refreshControl={<RefreshControl refreshing={refreshing} onRefresh={getQuestions} />}
        renderItem={({ item, index }) => {
          const arr = [item.commitments[0].commitment_icon];
          const questIcon = arr.filter(i => Boolean(i)).map(id => icon.find(o => o.id === id)?.image?.url);
          const imgUrl = APIURL + questIcon;
          function iconBgColor(){
            let bgColor
            switch (item.commitments[0].commitment_icon) {
              case 1:
                bgColor="#78bad3"
                break;
              case 3:
                bgColor = "#027a95"
                break;
              case 6:
                bgColor = "#027a95"
                break;
              case 4:
                bgColor = '#1fc191'
                break;
                case 5:
                bgColor = '#78bad3'
                break;
              case 2:
                bgColor = "#e4da4d"
                break;
              case 7:
                bgColor = "#1fc191"
                break;
              default:
                bgColor= "#fff"
                break;
            }
              return bgColor;
          }
          const backgroundColor = iconBgColor(item.commitments[0].commitment_icon)
          const data = [
            {
              
              title: (<>
               <View style={[styles.iconWrapper,{backgroundColor: backgroundColor}]}>
                 {
                   imgUrl.indexOf('.svg') > 0 ? <SvgUri uri={APIURL + questIcon} height={20} width={20} style={styles.iconColor}/> : null
                 } 
                </View>
                
                <Text style={styles.text}>{item.sortId}.</Text>
                <Text style={styles.text} key={item.description}>{item.description}</Text>

              </>),
              content:<View><OptionList key={item?.question_options.id} options={item?.question_options}></OptionList></View>
            },
          ];


          return (
            <View style={styles.groupOptions} key={index}>
              <Accordion style={styles.accordion} headerStyle={styles.headerStyle} contentStyle={styles.contentStyle} dataArray={data} opened={index} />
            </View>
          );
        }}
      />
    </View>
  );
};


Any ideas how to achieve what I want? Any answer would be appreciated, thanks.

2 Answers

you have a next code:

<Accordion
  style={styles.accordion}
  headerStyle={styles.headerStyle}
  contentStyle={styles.contentStyle}
  dataArray={data}
  opened={index} // here you should have "isAccordionOpen"
/>

and handle a variable in state your Step3 component.

In this function you should to change this variable "isAccordionOpen"

const clickedRadio = () => {
  const selectedOption = { [item.question]: { ...item } };
  setAnswers({ ...answers, ...selectedOption });
}

As I have checked in the docs and Galio Library there seems no prop to manage Accordion after the first render cycle.

We can only manage the Accordion initially on the first render.

If you have to manage it then you have to make changes in the Galio library code.

Here I am attaching the Sample code base, Hoping that it might help you.

Sample Code:

import React, { useState } from 'react'
import { View } from 'react-native'
import { Accordion, Block, Checkbox } from 'galio-framework';

const App = () => {
  const [openIndex, setOpenIndex] = useState(-1)

  const radioClickHandler = (id, status) => {
    setOpenIndex(-1)
  }

  const data = [
    {
      title: "First Chapter",
      content: (
        <Checkbox
          onChange={radioClickHandler.bind(null, 'first')}
          color="primary"
          label="Primary Checkbox"
        />
      )
   },
   {
    title: "Second Chapter",
    content: (
        <Checkbox
          onChange={radioClickHandler.bind(null, 'second')}
          color="primary"
          label="Secondary Checkbox"
        />
      )
    }
  ]

  const onOpen = (prop) => {
    setOpenIndex(prop?.title === "First Chapter" ? 0 : 1)
  }

  return (
    <View style={{ flex: 1, justifyContent: 'center' }}>
      <Block style={{ height: 200 }}>
        <Accordion
          dataArray={data}
          opened={openIndex}
          onAccordionOpen={onOpen}
        />
      </Block>
    </View>
  )
}

export default App

Here are the changes in the library code to manage the collapse Accordion Component.

file Path: 'node_modules/galio-framework-src-Accordion.js'

Add Below Code

  const [selected, setSelected] = useState(opened);

  useEffect(() => {
    setSelected(opened)
  }, [opened])
Related