Skip to content

Custom UI Sample React Native

Hudson_BuildService edited this page Jan 9, 2026 · 1 revision
const HomeView = () => {
    const [dialogHidden, setDialogHidden] = useState(true);
    const [config, setConfig] = useState({});

    useEffect(() => {
        async function runAsync() {
            const configuredServers = await ServerSdk.getServers();
            const servers: IServerModel[] = [];
            for (const server of configuredServers) {
                servers.push(server);
            }

            if (servers.length !== 0 && servers[0] != null) {
                const { serverId } = servers[0];

                TriggerSdk.setCallback(serverId, <PorgramKey>);

                await TriggerSdk.triggerDownload(serverId, <PorgramKey>);
            }
        }
        runAsync();
    }, []);

    useEffect(() => {
        const webview: EmitterSubscription = TriggerManager.setOnWebSurveyStart(onWebSurvey);
        const surveyStart: EmitterSubscription = TriggerManager.setOnSurveyStart(onSurveyStart);
        const scenarioLoad: EmitterSubscription = TriggerManager.setOnScenarioLoad(onScenarioLoad);
        const scenarioError: EmitterSubscription = TriggerManager.setOnScenarioError(onScenarioError);

        return () => {
            webview.remove();
            surveyStart.remove();
            scenarioLoad.remove();
            scenarioError.remove();
        };
    });

    const onWebSurvey = (events: IWebSurveyModel) => {
        // Show web survey
    };

    const onSurveyStart = (events: ISurveyModel) => {
        const { serverId, programKey, surveyId } = events;
        const customData = {};
        const respondentValues = {};
        SurveySdk.startSurvey(serverId, programKey, surveyId, customData, respondentValues);

        setDialogHidden(false);
        setConfig(events);
    };

    const onScenarioLoad = (events: IScenarioCallback) => {
        // on scenario script starts
    };

    const onScenarioError = (events: IScenarioCallback) => {
        // when scenario scripting contains error
    };

    const onDialogCloseAction = () => {
        setDialogHidden(true);
    };

    return (
        <View style={{ flex: 1 }}>
            <DialogView hidden={dialogHidden} onClose={onDialogCloseAction} config={config} />
        </View>
    );
};
export default HomeView;

const SurveyDialogView = (props: IDialogViewProps) => {
    const [infos, setInfos] = useState<IDefaultQuestion[]>([]);
    const [showFinished, setShowFinished] = useState<IFinishedConfig>({ finished: false, message: '' });
    const [pageControl, setPageControl] = useState<PageControl>();

    const onSurveyQuit = (_: { [key: string]: string }) => {
        // Survey quit by user
        props.onClose();
    };

    const onSurveyErrored = async (_: ISurveyErrored) => {
        // Survey contains error
        setShowFinished({
            finished: true,
            message: 'Sorry an error happen'
        });
    };

    const onSurveyFinished = async (_: ISurveyFinished) => {
        // Survey completed
        setShowFinished({
            finished: true,
            message: 'Thank you!'
        });
    };

    const onSurveyPageReady = async (control: PageControl) => {
        setShowFinished({
            finished: false,
            message: ''
        });
        // Set visibilities for navigation buttons
        setPageControl(control);

        // Fetch all questions for the page
        const questions = await control.getQuestion();
        setInfos(questions);
    };

    useEffect(() => {
        const pageReady: EmitterSubscription = SurveyFrameManager.setOnSurveyPageReady(onSurveyPageReady);
        const finished: EmitterSubscription = SurveyFrameManager.setOnSurveyFinished(onSurveyFinished);
        const errored: EmitterSubscription = SurveyFrameManager.setOnSurveyErrored(onSurveyErrored);
        const quit: EmitterSubscription = SurveyFrameManager.setOnSurveyQuit(onSurveyQuit);

        return () => {
            pageReady.remove();
            finished.remove();
            errored.remove();
            quit.remove();
        };
    });

    const onCloseAction = async () => {
        if (!pageControl) {
            return;
        }

        if (!showFinished.finished) {
            await pageControl.quit(true);
        } else {
            props.onClose();
        }
    };

    const onBackAction = async () => {
        if (!pageControl) {
            return;
        }

        await pageControl.back();
    };

    const onNextAction = async () => {
        if (!pageControl) {
            return;
        }

        await pageControl.next();
    };

    const renderFinishedPage = () => {
        return (
            <View>
                <Text style={styles.title}>{showFinished.message}</Text>
            </View>
        );
    };

    const renderQuestion = () => {
        if (!pageControl) {
            return [];
        }

        const elements: JSX.Element[] = [];
        // Loop through question in current survey page, and generate Views
        for (const info of infos) {
            switch (info.nodeType) {
                // If question type is TEXT
                case NodeType.Text: {
                    // PageControl is passed to the question
                    // 1. to fetch the current answers set
                    // 2. Interaction like answering question
                    elements.push(<QuestionTextView key={info.id} info={info} pageControl={pageControl} />);
                    break;
                }
                // ... More question type intergrations
            }
        }
        return elements;
    };

    const render = () => {
        if (props.hidden || !pageControl) {
            return <View />;
        }

        return (
            <View style={styles.container}>
                <View style={styles.topView}>
                    <Button title={'Close'} color={'#ff0000'} onPress={onCloseAction} />
                </View>
                <View style={styles.fillView}>
                    <View style={{ display: showFinished.finished ? 'flex' : 'none', justifyContent: 'center', alignItems: 'center' }}>{renderFinishedPage()}</View>
                    <ScrollView style={{ paddingHorizontal: 16, display: showFinished.finished ? 'none' : 'flex' }}>{renderQuestion()}</ScrollView>
                </View>
                <View style={styles.bottomView}>
                    <View>{!showFinished.finished && pageControl.showBackward && <Button onPress={onBackAction} title={pageControl.backwardText} />}</View>
                    <View>{!showFinished.finished && pageControl.showForward && <Button onPress={onNextAction} title={pageControl.forwardText} />}</View>
                </View>
            </View>
        );
    };

    return render();
};

export default SurveyDialogView;
const styles = StyleSheet.create({
    container: {
        position: 'absolute',
        top: 0,
        bottom: 0,
        left: 0,
        right: 0,
        flex: 1,
        flexDirection: 'column',
        justifyContent: 'space-between',
        alignItems: 'stretch',
        backgroundColor: '#fff'
    },
    topView: {
        padding: 16,
        justifyContent: 'center',
        alignItems: 'flex-end'
    },
    bottomView: {
        padding: 16,
        flexDirection: 'row',
        justifyContent: 'space-between',
        alignItems: 'center'
    },
    fillView: {
        flex: 1,
        justifyContent: 'flex-start',
        alignItems: 'stretch'
    },
    title: {
        fontSize: 16,
        color: '#000000',
        fontWeight: '500',
        justifyContent: 'center',
        alignItems: 'center'
    }
});

const QuestionTextView = (props: IQuestionProps) => {
    const styles = require('../utils/styles');

    const [text, setText] = useState('');
    const { pageControl } = props;

    useEffect(() => {
        async function fetchData() {
            // 1. fetch the current answer that is set and display it
            const answer = await pageControl.getText(props.info.id);
            setText(answer);
        }
        fetchData();
    }, [pageControl, props.info.id]);

    const onChangeText = async (text: string) => {
        setText(text);
        // 2. set the result to the question
        await pageControl.setText(props.info.id, text);
    };

    return (
        <View key={props.info.id} style={styles.questionBottom}>
            <Text style={styles.questionTitle}>{props.info.title}</Text>
            <ErrorTextView errors={props.info.errors} />
            <TextInput
                value={text}
                multiline={true}
                numberOfLines={4}
                textAlignVertical={'top'}
                style={{ padding: 10, borderRadius: 8, borderColor: '#000000', borderWidth: 1 }}
                onChangeText={onChangeText}
            />
        </View>
    );
};

export default QuestionTextView;

Clone this wiki locally