semantic-ui-react#Select TypeScript Examples

The following examples show how to use semantic-ui-react#Select. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: voyagecalculator.tsx    From website with MIT License 4 votes vote down vote up
VoyageEditConfigModal = (props: VoyageEditConfigModalProps) => {
	const { updateConfig } = props;

	const [voyageConfig, setVoyageConfig] = React.useState(props.voyageConfig);

	const [modalIsOpen, setModalIsOpen] = React.useState(false);
	const [updateOnClose, setUpdateOnClose] = React.useState(false);
	const [options, setOptions] = React.useState(undefined);

	React.useEffect(() => {
		if (!modalIsOpen && updateOnClose) {
			updateConfig(voyageConfig);
			setUpdateOnClose(false);
		}

	}, [modalIsOpen]);

	const defaultSlots = [
		{ symbol: 'captain_slot', name: 'First Officer', skill: 'command_skill', trait: '' },
		{ symbol: 'first_officer', name: 'Helm Officer', skill: 'command_skill', trait: '' },
		{ symbol: 'chief_communications_officer', name: 'Communications Officer', skill: 'diplomacy_skill', trait: '' },
		{ symbol: 'communications_officer', name: 'Diplomat', skill: 'diplomacy_skill', trait: '' },
		{ symbol: 'chief_security_officer', name: 'Chief Security Officer', skill: 'security_skill', trait: '' },
		{ symbol: 'security_officer', name: 'Tactical Officer', skill: 'security_skill', trait: '' },
		{ symbol: 'chief_engineering_officer', name: 'Chief Engineer', skill: 'engineering_skill', trait: '' },
		{ symbol: 'engineering_officer', name: 'Engineer', skill: 'engineering_skill', trait: '' },
		{ symbol: 'chief_science_officer', name: 'Chief Science Officer', skill: 'science_skill', trait: '' },
		{ symbol: 'science_officer', name: 'Deputy Science Officer', skill: 'science_skill', trait: '' },
		{ symbol: 'chief_medical_officer', name: 'Chief Medical Officer', skill: 'medicine_skill', trait: '' },
		{ symbol: 'medical_officer', name: 'Ship\'s Counselor', skill: 'medicine_skill', trait: '' }
	];
	const crewSlots = voyageConfig.crew_slots ?? defaultSlots;
	crewSlots.sort((s1, s2) => CONFIG.VOYAGE_CREW_SLOTS.indexOf(s1.symbol) - CONFIG.VOYAGE_CREW_SLOTS.indexOf(s2.symbol));

	return (
		<Modal
			open={modalIsOpen}
			onClose={() => setModalIsOpen(false)}
			onOpen={() => setModalIsOpen(true)}
			trigger={<Button size='small'><Icon name='edit' />Edit</Button>}
		>
			<Modal.Header>Edit Voyage</Modal.Header>
			<Modal.Content scrolling>
				{renderContent()}
			</Modal.Content>
			<Modal.Actions>
				<Button positive onClick={() => setModalIsOpen(false)}>
					Close
				</Button>
			</Modal.Actions>
		</Modal>
	);

	function renderContent(): JSX.Element {
		if (!modalIsOpen) return (<></>);

		if (!options) {
			// Renders a lot faster by using known voyage traits rather than calculate list from all possible traits
			const knownShipTraits = ['andorian','battle_cruiser','borg','breen','cardassian','cloaking_device',
				'dominion','emp','explorer','federation','ferengi','freighter','historic','hologram',
				'klingon','malon','maquis','orion_syndicate','pioneer','reman','romulan','ruthless',
				'scout','spore_drive','terran','tholian','transwarp','vulcan','warship','war_veteran','xindi'];
			const knownCrewTraits = ['android','astrophysicist','bajoran','borg','brutal',
				'cardassian','civilian','communicator','costumed','crafty','cultural_figure','cyberneticist',
				'desperate','diplomat','doctor','duelist','exobiology','explorer','federation','ferengi',
				'gambler','hero','hologram','human','hunter','innovator','inspiring','jury_rigger','klingon',
				'marksman','maverick','pilot','prodigy','resourceful','romantic','romulan',
				'saboteur','scoundrel','starfleet','survivalist','tactician','telepath','undercover_operative',
				'veteran','villain','vulcan'];

			const skillsList = [];
			for (let skill in CONFIG.SKILLS) {
				skillsList.push({
					key: skill,
					value: skill,
					text: CONFIG.SKILLS[skill]
				});
			}

			const shipTraitsList = knownShipTraits.map(trait => {
				return {
					key: trait,
					value: trait,
					text: allTraits.ship_trait_names[trait]
				};
			});
			shipTraitsList.sort((a, b) => a.text.localeCompare(b.text));

			const crewTraitsList = knownCrewTraits.map(trait => {
				return {
					key: trait,
					value: trait,
					text: allTraits.trait_names[trait]
				};
			});
			crewTraitsList.sort((a, b) => a.text.localeCompare(b.text));

			setOptions({ skills: skillsList, ships: shipTraitsList, traits: crewTraitsList });
			return (<></>);
		}

		return (
			<React.Fragment>
				<Message>Editing this voyage will reset all existing recommendations and estimates.</Message>
				<Form>
					<Form.Group>
						<Form.Select
							label='Primary skill'
							options={options.skills}
							value={voyageConfig.skills.primary_skill ?? 'command_skill'}
							onChange={(e, { value }) => setSkill('primary_skill', value)}
							placeholder='Primary'
						/>
						<Form.Select
							label='Secondary skill'
							options={options.skills}
							value={voyageConfig.skills.secondary_skill ?? 'science_skill'}
							onChange={(e, { value }) => setSkill('secondary_skill', value)}
							placeholder='Secondary'
						/>
						<Form.Select
							search clearable
							label='Ship trait'
							options={options.ships}
							value={voyageConfig.ship_trait}
							onChange={(e, { value }) => setShipTrait(value)}
							placeholder='Ship trait'
						/>
					</Form.Group>
				</Form>
				<Table compact striped>
					<Table.Header>
						<Table.Row>
							<Table.HeaderCell textAlign='center'>Skill</Table.HeaderCell>
							<Table.HeaderCell>Seat</Table.HeaderCell>
							<Table.HeaderCell>Trait</Table.HeaderCell>
						</Table.Row>
					</Table.Header>
					<Table.Body>
						{crewSlots.map((seat, idx) => (
							<Table.Row key={seat.symbol}>
								{ idx % 2 == 0 ?
									(
										<Table.Cell rowSpan='2' textAlign='center'>
											<img alt="{seat.skill}" src={`${process.env.GATSBY_ASSETS_URL}atlas/icon_${seat.skill}.png`} style={{ height: '2em' }} />
										</Table.Cell>
									)
									: (<></>)
								}
								<Table.Cell>{seat.name}</Table.Cell>
								<Table.Cell>
									<Dropdown search selection clearable
										options={options.traits}
										value={seat.trait}
										onChange={(e, { value }) => setSeatTrait(seat.symbol, value)}
										placeholder='Trait'
									/>
								</Table.Cell>
							</Table.Row>
						))}
					</Table.Body>
				</Table>
			</React.Fragment>
		);
	}

	function setSkill(prime: string, value: string): void {
		// Flip skill values if changing to value that's currently set as the other prime
		if (prime == 'primary_skill' && value == voyageConfig.skills.secondary_skill)
			voyageConfig.skills.secondary_skill = voyageConfig.skills.primary_skill;
		else if (prime == 'secondary_skill' && value == voyageConfig.skills.primary_skill)
			voyageConfig.skills.primary_skill = voyageConfig.skills.secondary_skill;
		voyageConfig.skills[prime] = value;
		setVoyageConfig({...voyageConfig});
		setUpdateOnClose(true);
	}

	function setShipTrait(value: string): void {
		voyageConfig.ship_trait = value;
		setVoyageConfig({...voyageConfig});
		setUpdateOnClose(true);
	}

	function setSeatTrait(seat: symbol, value: string): void {
		voyageConfig.crew_slots.find(s => s.symbol === seat).trait = value;
		setVoyageConfig({...voyageConfig});
		setUpdateOnClose(true);
	}
}
Example #2
Source File: voyagecalculator.tsx    From website with MIT License 4 votes vote down vote up
VoyageInput = (props: VoyageInputProps) => {
	const { voyageConfig, myCrew, allShips, useInVoyage } = props;

	const [bestShip, setBestShip] = React.useState(undefined);
	const [consideredCrew, setConsideredCrew] = React.useState([]);
	const [calculator, setCalculator] = React.useState(isMobile ? 'ussjohnjay' : 'iampicard');
	const [calcOptions, setCalcOptions] = React.useState({});
	const [telemetryOptOut, setTelemetryOptOut] = useStateWithStorage('telemetryOptOut', false, { rememberForever: true });
	const [requests, setRequests] = React.useState([]);
	const [results, setResults] = React.useState([]);

	React.useEffect(() => {
		// Note that allShips is missing the default ship for some reason (1* Constellation Class)
		//	This WILL break voyagecalculator if that's the only ship a player owns
		const consideredShips = [];
		allShips.filter(ship => ship.owned).forEach(ship => {
			const traited = ship.traits.find(trait => trait === voyageConfig.ship_trait);
			let entry = {
				ship: ship,
				score: ship.antimatter + (traited ? 150 : 0),
				traited: traited,
				bestIndex: Math.min(ship.index.left, ship.index.right)
			};
			consideredShips.push(entry);
		});
		consideredShips.sort((a, b) => {
			if (a.score === b.score) return a.bestIndex - b.bestIndex;
			return b.score - a.score;
		});
		setBestShip(consideredShips[0]);
		setRequests([]);
		setResults([]);
	}, [voyageConfig]);

	React.useEffect(() => {
		return function cleanup() {
			// Cancel active calculations when leaving page
			requests.forEach(request => {
				if (request.calcState == CalculatorState.InProgress)
					request.abort();
			});
		}
	}, []);

	// Scroll here when calculator started, finished
	const topAnchor = React.useRef(null);

	const calculators = CALCULATORS.helpers.map(helper => {
		return { key: helper.id, value: helper.id, text: helper.name };
	});
	calculators.push({ key: 'all', value: 'all', text: 'All calculators (slower)' });

	return (
		<React.Fragment>
			<div ref={topAnchor} />
			{renderBestShip()}
			{renderResults()}
			{requests.length > 0 && <Header as='h3'>Options</Header>}
			<Form>
				<InputCrewOptions myCrew={myCrew} updateConsideredCrew={setConsideredCrew} />
				<Form.Group inline>
					<Form.Field
						control={Select}
						label='Calculator'
						options={calculators}
						value={calculator}
						onChange={(e, { value }) => setCalculator(value)}
						placeholder='Select calculator'
					/>
					{CALCULATORS.fields.filter(field => field.calculators.includes(calculator) || calculator == 'all').map(field => (
						<Form.Field
							key={field.id}
							control={Select}	/* Only control allowed at the moment */
							label={field.name}
							options={field.options}
							value={calcOptions[field.id] ?? field.default}
							placeholder={field.description}
							onChange={(e, { value }) => setCalcOptions(prevOptions =>
								{
									const newValue = { [field.id]: value };
									return {...prevOptions, ...newValue};
								}
							)}
						/>
					))}
				</Form.Group>

				<Form.Group>
					<Form.Button primary onClick={() => startCalculation()}>
						Calculate best crew selection
					</Form.Button>
					{voyageConfig.state &&
						<Form.Button onClick={()=> useInVoyage()}>
							Return to in voyage calculator
						</Form.Button>
					}
				</Form.Group>
			</Form>
			<Message style={{ marginTop: '2em' }}>
				<Message.Content>
					<Message.Header>Privacy Notice</Message.Header>
					<p>We use anonymous statistics aggregated from voyage calculations to improve DataCore and power our <b><Link to='/hall_of_fame'>Voyage Hall of Fame</Link></b>.</p>
					<Form>
						<Form.Field
							control={Checkbox}
							label={<label>Permit DataCore to collect anonymous voyage stats</label>}
							checked={!telemetryOptOut}
							onChange={(e, { checked }) => setTelemetryOptOut(!checked) }
						/>
					</Form>
				</Message.Content>
			</Message>
		</React.Fragment>
	);

	function renderBestShip(): JSX.Element {
		if (!bestShip) return (<></>);

		const direction = bestShip.ship.index.right < bestShip.ship.index.left ? 'right' : 'left';
		const index = bestShip.ship.index[direction] ?? 0;

		return (
			<Card fluid>
				<Card.Content>
					<Image floated='left' src={`${process.env.GATSBY_ASSETS_URL}${bestShip.ship.icon.file.substr(1).replace('/', '_')}.png`} style={{ height: '4em' }} />
					<Card.Header>{bestShip.ship.name}</Card.Header>
					<p>best ship{bestShip.traited && (<span style={{ marginLeft: '1em' }}>{` +`}{allTraits.ship_trait_names[voyageConfig.ship_trait]}</span>)}</p>
					<p style={{ marginTop: '.5em' }}>Tap <Icon name={`arrow ${direction}`} />{index} time{index != 1 ? 's' : ''} on your voyage ship selection screen to select {bestShip.ship.name}.</p>
				</Card.Content>
			</Card>
		);
	}

	function renderResults(): JSX.Element {
		if (results.length == 0)
			return (<></>);

		const showPopup = (result) => <Popup basic content={<p>{result.result.postscript}</p>} trigger={<p>{result.name}</p>} />
		const panes = results.map(result => ({
			menuItem: { key: result.id, content: result.result ? showPopup(result) : result.name },
			render: () => (
				<VoyageResultPane result={result.result}
					requests={requests} requestId={result.requestId}
					calcState={result.calcState} abortCalculation={abortCalculation}
				/>
			)
		}));

		return (
			<React.Fragment>
				<Header as='h3'>Recommended Lineups</Header>
				<Tab menu={{ pointing: true }}
					panes={panes}
				/>
			</React.Fragment>
		);
	}

	function scrollToAnchor(): void {
		if (!topAnchor.current) return;
		topAnchor.current.scrollIntoView({
			behavior: 'smooth'
		}, 500);
	}

	function startCalculation(): void {
		const helperConfig = {
			voyageConfig, bestShip, consideredCrew, calcOptions,
			resultsCallback: handleResults,
			isMobile
		};
		CALCULATORS.helpers.forEach(helper => {
			if (helper.id == calculator || calculator == 'all') {
				const request = helper.helper(helperConfig);
				requests.push(request);
				results.push({
					id: request.id,
					requestId: request.id,
					name: 'Calculating...',
					calcState: CalculatorState.InProgress
				});
				request.start();
			}
		});
		setRequests([...requests]);
		setResults([...results]);
		scrollToAnchor();
	}

	function handleResults(requestId: string, reqResults: any[], calcState: number): void {
		reqResults.forEach((reqResult, idx) => {
			// Update existing pane with results
			if (idx == 0) {
				setResults(prevResults => {
					const result = prevResults.find(r => r.id == requestId);
					if (calcState == CalculatorState.Done) {
						result.name = formatTime(reqResult.estimate.refills[0].result);
						result.calcState = CalculatorState.Done;
						sendTelemetry(requestId, reqResult);
					}
					result.result = reqResult;
					return [...prevResults];
				});
			}
			// Add new panes if multiple results generated by this request
			else {
				setResults(prevResults => [...prevResults, {
					id: requestId+'-'+idx,
					requestId,
					name: formatTime(reqResult.estimate.refills[0].result),
					calcState: CalculatorState.Done,
					result: reqResult
				}]);
			}
		});
		if (calcState == CalculatorState.Done) scrollToAnchor();
	}

	function abortCalculation(requestId: string): void {
		const request = requests.find(r => r.id == requestId);
		if (request) {
			request.abort();
			setResults(prevResults => {
				const result = prevResults.find(prev => prev.id == requestId);
				if (result.result) {
					result.name = formatTime(result.result.estimate.refills[0].result);
					result.calcState = CalculatorState.Done;
				}
				else {
					const index = prevResults.findIndex(prev => prev.id == requestId);
					prevResults.splice(index, 1);
				}
				return [...prevResults];
			});
		}
	}

	function sendTelemetry(requestId: string, result: any): void {
		if (telemetryOptOut) return;
		const request = requests.find(r => r.id == requestId);
		const estimatedDuration = result.estimate.refills[0].result*60*60;
		try {
			fetch(`${process.env.GATSBY_DATACORE_URL}api/telemetry`, {
				method: 'post',
				headers: {
					'Content-Type': 'application/json'
				},
				body: JSON.stringify({
					type: 'voyageCalc',
					data: {
						voyagers: result.entries.map((entry) => entry.choice.symbol),
						estimatedDuration,
						calculator: request ? request.calculator : ''
					}
				})
			});
		}
		catch (err) {
			console.log('An error occurred while sending telemetry', err);
		}
	}
}