import { useEffect, useState } from 'react'; import { Text, Box, Newline } from 'ink'; import { checkCredentials, getCredentials, hasCredentials, removeCredentials, saveCredentials, } from '../utils/crystallize.js'; import { PimAuthenticatedUser, PimCredentials } from '../../types.js'; import { Select } from './Select.js'; import { colors } from '../../config/colors.js'; import { UncontrolledTextInput } from 'ink-text-input'; import React from 'react'; type YesOrNo = 'yes' | 'no'; type UseExistingCredentials = YesOrNo | 'remove'; type SaveCredentials = YesOrNo; export const SetupCredentials: React.FC<{ dispatch: (authicatedUser: PimAuthenticatedUser, credentials: PimCredentials) => void; }> = ({ dispatch }) => { const [user, setUser] = useState(null); const [credentials, setCredentials] = useState(); const [askForInput, setAskForInput] = useState(false); const [askForSaving, setAskForSaving] = useState(false); useEffect(() => { hasCredentials().then((hasCredentials: boolean) => { if (!hasCredentials) { setAskForInput(true); return; } getCredentials().then((credentials: PimCredentials) => { setCredentials(credentials); }); }); }, []); useEffect(() => { if (!credentials || user) { return; } checkCredentials(credentials).then((authicatedUser?: PimAuthenticatedUser) => { if (!authicatedUser) { setAskForInput(true); return; } setUser(authicatedUser); }); }, [credentials]); if (user && !askForInput && !askForSaving) { return ( { switch (answer) { case 'remove': removeCredentials(); case 'no': setAskForInput(true); setUser(null); break; case 'yes': dispatch(user, credentials!); return; } }} /> ); } if (askForInput) { return ( { setCredentials(credentials); setUser(user); setAskForSaving(true); setAskForInput(false); }} /> ); } if (askForSaving) { return ( { dispatch(user!, credentials!); }} /> ); } return Verifying Crystallize Access Tokens...; }; const ShouldWeUsedExistingTokenQuestion: React.FC<{ user: PimAuthenticatedUser; onAnswer: (answer: UseExistingCredentials) => void; }> = ({ onAnswer, user }) => { return ( Hello{' '} {user.firstName} {user.lastName} {' '} ({user.email}) We found existing valid Crystallize Access Tokens. Want to use it? styles={{ compact: true }} onSelect={onAnswer} options={[ { value: 'yes', label: 'Yes', }, { value: 'no', label: 'No', }, { value: 'remove', label: 'Wait, what? Remove the stored access tokens please', }, ]} /> ); }; const AskForCredentials: React.FC<{ onValidCredentials: (credentials: PimCredentials, user: PimAuthenticatedUser) => void; }> = ({ onValidCredentials }) => { const [inputCredentials, setInputCredentials] = useState>(); const [error, setError] = useState(null); useEffect(() => { if (!inputCredentials?.ACCESS_TOKEN_SECRET) { return; } checkCredentials({ ACCESS_TOKEN_ID: inputCredentials?.ACCESS_TOKEN_ID || '', ACCESS_TOKEN_SECRET: inputCredentials?.ACCESS_TOKEN_SECRET || '', }).then((authicatedUser?: PimAuthenticatedUser) => { if (!authicatedUser) { setError('⚠️ Invalid tokens supplied. Please try again ⚠️'); setInputCredentials({}); return; } onValidCredentials(inputCredentials as PimCredentials, authicatedUser); }); }, [inputCredentials]); const isLoading = !!inputCredentials?.ACCESS_TOKEN_ID && !!inputCredentials?.ACCESS_TOKEN_SECRET; return ( <> Please provide Access Tokens to bootstrap the tenant Learn about access tokens: https://crystallize.com/learn/developer-guides/access-tokens {error && ( {error} )} {!isLoading && !inputCredentials?.ACCESS_TOKEN_ID && ( <> Access Token ID: setInputCredentials({ ACCESS_TOKEN_ID: value, }) } /> )} {!isLoading && inputCredentials?.ACCESS_TOKEN_ID && !inputCredentials?.ACCESS_TOKEN_SECRET && ( <> Access Token ID: *** Access Token Secret: setInputCredentials({ ...inputCredentials, ACCESS_TOKEN_SECRET: value, }) } /> )} {isLoading && Verifying Crystallize Access Tokens...} ); }; const AskToSaveCredentials: React.FC<{ credentials: PimCredentials; user: PimAuthenticatedUser; onAnswered: () => void; }> = ({ credentials, user, onAnswered }) => { return ( Hello {user.firstName} {user.lastName} ({user.email}) Would you like to save the access tokens for future use? styles={{ compact: true }} onSelect={(answer) => { if (answer === 'yes') { saveCredentials(credentials); } onAnswered(); }} options={[ { value: 'yes', label: 'Yes, please', }, { value: 'no', label: 'No, thanks', }, ]} /> ); };