react-i18next#Trans TypeScript Examples
The following examples show how to use
react-i18next#Trans.
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: index.tsx From genshin-optimizer with MIT License | 8 votes |
export default function ArtifactInfoDisplay() {
const { t } = useTranslation("artifact")
return <Grid container spacing={1} >
<Grid item xs={12} lg={5} xl={4}>
<ImgFullwidth src={artifactcard} />
</Grid>
<Grid item xs={12} lg={7} xl={8}>
<Trans t={t} i18nKey="info.section1">
<Typography variant="h5">Substat rolls</Typography>
<Typography gutterBottom>The <b>number of rolls</b> a substat has is shown to the left of the substat. As the number gets higher, the substat is more colorful:<Colors />.</Typography>
<Typography variant="h5">Substat Roll Value</Typography>
<Typography gutterBottom>The Roll Value(RV) of an subtat is a percentage of the current value over the highest potential 5<Stars stars={1} /> value. From the Image, the maximum roll value of CRIT DMG is 7.8%. In RV: <b>5.8/7.8 = 69.2%.</b></Typography>
<Typography variant="h5">Current Roll Value vs. Maximum Roll Value</Typography>
<Typography gutterBottom>When a 5<Stars stars={1} /> have 9(4+5) total rolls, with each of the rolls having the highest value, that is defined as a 900% RV artifact. However, most of the artifacts are not this lucky. The <b>Current RV</b> of an artifact is a percentage over that 100% artifact. The <b>Maximum RV</b> is the maximum possible RV an artifact can achieve, if the remaining artifact rolls from upgrades are the hightest possible value.</Typography>
<Typography variant="h5">Locking an artifact</Typography>
<Typography>By locking an artifact <FontAwesomeIcon icon={faBan} />, This artifact will not be picked up by the build generator for optimization. An equipped artifact is locked by default.</Typography>
</Trans>
</Grid>
<Grid item xs={12} lg={6} xl={7} >
<Trans t={t} i18nKey="info.section2">
<Typography variant="h5">Artifact Editor</Typography>
<Typography gutterBottom>A fully featured artifact editor, that can accept any 3<Stars stars={1} /> to 5<Stars stars={1} /> Artifact. When a substat is inputted, it can calculate the exact roll values. It will also make sure that you have the correct number of rolls in the artifact according to the level, along with other metrics of validation.</Typography>
<Typography variant="h5">Scan screenshots</Typography>
<Typography gutterBottom>Manual input is not your cup of tea? You can scan in your artifacts with screenshots! On the Artifact Editor, click the <SqBadge color="info">Show Me How!</SqBadge> button to learn more.</Typography>
<Typography variant="h6">Automatic Artifact Scanner</Typography>
<Typography gutterBottom>If you are playing Genshin on PC, you can download a tool that automatically scans all your artifacts for you, and you can then import that data in <FontAwesomeIcon icon={faCog} /> Database. <Link component={RouterLink} to="/scanner">Click here</Link> for a list of scanners that are compatible with GO.</Typography>
<Typography variant="h5">Duplicate/Upgrade artifact detection</Typography>
<Typography>Did you know GO can detect if you are adding a <b>duplicate</b> artifact that exists in the system? It can also detect if the current artifact in editor is an <b>upgrade</b> of an existing artifact as well. Once a duplicate/upgrade is detected, a preview will allow you to compare the two artifacts in question(See Image).</Typography>
</Trans>
</Grid>
<Grid item xs={12} lg={6} xl={5}>
<ImgFullwidth src={artifacteditor} />
</Grid>
<Grid item xs={12} lg={7} xl={6}>
<ImgFullwidth src={artifactfilter} />
</Grid>
<Grid item xs={12} lg={5} xl={6}>
<Trans t={t} i18nKey="info.section3">
<Typography variant="h5">Artifact Inventory</Typography>
<Typography gutterBottom>All your artifacts that you've added to GO is displayed here. The filters here allow you to further refine your view of your artifacts. </Typography>
<Typography variant="h5">Example: Finding Fodder Artifacts</Typography>
<Typography>By utilizing the artifact filter, and the artifact RV, you can quickly find artifacts to feed as food.</Typography>
<Typography>In this example, the filters are set thusly: </Typography>
<Typography component="div" >
<ul>
<li>Limit level to 0-8.</li>
<li>Unlocked artifacts in Inventory.</li>
<li>Removing the contribution of flat HP, flat DEF and Energy Recharge to RV calculations.</li>
<li>Sorted by Ascending Max Roll Value.</li>
</ul>
</Typography>
<Typography>This will filter the artifact Inventory by the lowest RV artifacts, for desired substats.</Typography>
</Trans>
</Grid>
</Grid>
}
Example #2
Source File: Welcome.tsx From NewWorldMinimap with MIT License | 6 votes |
export default function Welcome() {
const { classes } = useStyles();
const { t } = useTranslation();
function tryForceMap() {
backgroundController.debug_setGameRunning(true);
}
return <div className={classes.root}>
<img className={classes.background} src='/img/map-crop.svg' />
<h2>{t('welcome.title')}</h2>
<p>{t('welcome.primary')}</p>
<p>{t('welcome.settings')}</p>
<p>
<Trans i18nKey='welcome.discord' tOptions={{ discord: discordUrl }}>
Join <a className={classes.discordLink} href={discordUrl} target='_blank'>discord</a>!
</Trans>
</p>
{!NWMM_APP_BUILD_PRODUCTION && <>
<hr />
<p>{t('welcome.devBuild')}</p>
<Button onClick={tryForceMap}>{t('welcome.forceMap')}</Button>
</>}
<div className={classes.gap} />
<LanguagePicker />
</div>;
}
Example #3
Source File: PeriodSwitch.tsx From nosgestesclimat-site with MIT License | 6 votes |
export default function PeriodSwitch() {
const dispatch = useDispatch()
const currentUnit = useSelector(targetUnitSelector)
const units = ['€/mois', '€/an']
return (
<span id="PeriodSwitch">
<span className="base ui__ small radio toggle">
{units.map(unit => (
<label key={unit}>
<input
name="defaultUnit"
type="radio"
value={unit}
onChange={() => dispatch(updateUnit(unit))}
checked={currentUnit === unit}
/>
<span>
<Trans>{unit}</Trans>
</span>
</label>
))}
</span>
</span>
)
}
Example #4
Source File: About.tsx From tobira with Apache License 2.0 | 6 votes |
About: React.FC = () => {
const { t } = useTranslation();
return (
<div css={{ margin: "0 auto", maxWidth: 600 }}>
<PageTitle title={t("about-tobira.title")} />
<p css={{ margin: "16px 0" }}>
<Trans i18nKey="about-tobira.body">
Description.
<a href="https://github.com/elan-ev/tobira">GitHub repo</a>
</Trans>
</p>
<h2>{t("version-information")}</h2>
<code>tobira {CONFIG.version}</code>
</div>
);
}
Example #5
Source File: SortByButton.tsx From genshin-optimizer with MIT License | 6 votes |
// Assumes that all the sortKeys has corresponding translations in ui.json sortMap
export default function SortByButton({ sortKeys, value, onChange, ascending, onChangeAsc, ...props }: SortByButtonProps) {
const { t } = useTranslation("ui")
return <Box display="flex" alignItems="center" gap={1}>
<Trans t={t} i18nKey={t("sortBy") as any}>Sort by: </Trans>
<ButtonGroup {...props} >
<DropdownButton title={<Trans t={t} i18nKey={t(`sortMap.${value}`) as any}>{{ value: t(`sortMap.${value}`) }}</Trans>}>
{sortKeys.map(key =>
<MenuItem key={key} selected={value === key} disabled={value === key} onClick={() => onChange(key)}>{t(`sortMap.${key}`) as any}</MenuItem>)}
</DropdownButton>
<Button onClick={() => onChangeAsc(!ascending)} startIcon={<FontAwesomeIcon icon={ascending ? faSortAmountDownAlt : faSortAmountUp} className="fa-fw" />}>
{ascending ? <Trans t={t} i18nKey="ascending" >Ascending</Trans> : <Trans t={t} i18nKey="descending" >Descending</Trans>}
</Button>
</ButtonGroup>
</Box>
}
Example #6
Source File: index.test.tsx From oasis-wallet-web with Apache License 2.0 | 6 votes |
jest.mock('react-i18next', () => ({
Trans: (({ i18nKey }) => <>{i18nKey}</>) as TransType,
useTranslation: () => {
return {
t: str => str,
i18n: {
changeLanguage: () => new Promise(() => {}),
},
} as UseTranslationResponse<'translation'>
},
}))
Example #7
Source File: WalletForm.tsx From subscan-multisig-react with Apache License 2.0 | 6 votes |
function confirmToAdd(accountExist: KeyringAddress, confirm: () => void) {
return Modal.confirm({
cancelText: <Trans>cancel</Trans>,
okText: <Trans>confirm</Trans>,
onOk: (close) => {
if (confirm) {
confirm();
}
close();
},
maskClosable: false,
closeIcon: false,
content: (
<div>
<p className="mb-4">
<Trans>
There is an account configured by the same member and threshold. Confirm to replace it with a new account?
</Trans>
</p>
<Descriptions column={1} size="small" title={<Trans>Origin Account</Trans>}>
<Descriptions.Item label={<Trans>name</Trans>}>{accountExist.meta.name}</Descriptions.Item>
<Descriptions.Item label={<Trans>threshold</Trans>}>
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
{(accountExist.meta as any).threshold}
</Descriptions.Item>
<Descriptions.Item label={<Trans>Create Time</Trans>}>
{format(accountExist.meta.whenCreated || 0, 'yyyy-MM-dd hh:mm:ss')}
</Descriptions.Item>
</Descriptions>
</div>
),
});
}
Example #8
Source File: NewUserMessage.tsx From TidGi-Desktop with Mozilla Public License 2.0 | 6 votes |
export function NewUserMessage(props: IProps): JSX.Element {
const { t } = useTranslation();
return (
<AddWorkspaceGuideInfoContainer onClick={async () => await window.service.window.open(WindowNames.addWorkspace)}>
{props.sidebar ? (
<>
<Arrow image={props.themeSource === 'dark' ? arrowWhite : arrowBlack} />
<TipWithSidebar id="new-user-tip">
<Trans t={t} i18nKey="AddWorkspace.MainPageTipWithSidebar">
<Tip2Text>Click</Tip2Text>
<Avatar>+</Avatar>
<Tip2Text>to get started!</Tip2Text>
</Trans>
</TipWithSidebar>
</>
) : (
<TipWithoutSidebar id="new-user-tip">
<Tip2Text>
<Trans t={t} i18nKey="AddWorkspace.MainPageTipWithoutSidebar">
<span>Click </span>
<strong>Workspaces > Add Workspace</strong>
<span>Or </span>
<strong>Click Here</strong>
<span> to get started!</span>
</Trans>
</Tip2Text>
</TipWithoutSidebar>
)}
</AddWorkspaceGuideInfoContainer>
);
}
Example #9
Source File: LanguagePicker.tsx From fishbowl with MIT License | 5 votes |
LanguagePicker = () => {
const classes = useStyles()
const { t, i18n } = useTranslation()
return (
<Box textAlign="center">
<ul className={classes.root}>
{SupportedLanguages.map((code) => (
<li key={code}>
<Chip
label={languageNameFromCode(code)}
variant="outlined"
color={code === i18n.language ? "primary" : "default"}
onClick={() => {
i18n.changeLanguage(code)
}}
/>
</li>
))}
<li>
<IconButton
component={Link}
size="small"
href="https://github.com/avimoondra/fishbowl#Localization"
target="_blank"
>
<AddCircleOutlineIcon />
</IconButton>
</li>
</ul>
<Typography color="textSecondary" variant="caption">
<Trans t={t} i18nKey="languagesPoweredBy">
{"Powered by our friends at "}
<Link href="https://locize.com" target="_blank">
{{ serviceName: "locize" }}
</Link>
.
</Trans>
</Typography>
</Box>
)
}
Example #10
Source File: disclamer-btn.component.tsx From cwa-quick-test-frontend with Apache License 2.0 | 5 votes |
DisclamerButton = (props: any) => {
const { t } = useTranslation();
const [show, setShow] = React.useState(false);
React.useEffect(() => {
setShow(props.firstTimeShow);
props.onInit();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return (
<>
<Image
src={SpeechBubbleImage}
className='speech-bubble'
onClick={() => { setShow(true) }}
/>
<Modal
contentClassName='data-modal'
show={show}
backdrop={true}
onHide={() => { setShow(false) }}
keyboard={false}
centered
>
<Modal.Header id='data-header' className='pb-0' >
<Row>
<Col >
<Card.Title className='m-0 jcc-xs-jcfs-md' as={'h2'} >
{t('translation:disclaimer-title')}</Card.Title>
</Col>
</Row>
</Modal.Header>
<Modal.Body className='bg-light py-0'>
<hr />
<h5 className='disclaimer-text'>
<Trans>{props.disclaimerText}</Trans>
</h5>
<hr />
<FormGroupConsentCkb controlId='formDoNotShowCheckbox' title={t('translation:disclaimer-do-not-show')}
onChange={(evt: any) => props.onCheckChange(evt.currentTarget.checked)}
type='checkbox'
checked={props.checked}
/>
</Modal.Body>
<Modal.Footer id='data-footer'>
<Container className='p-0'>
<Row className='justify-content-end'>
<Col xs='6' className='p-0'>
<Button
className='py-0'
block
onClick={() => { setShow(false) }}
>
{t('translation:ok')}
</Button>
</Col>
</Row>
</Container>
</Modal.Footer>
</Modal>
</>
)
}
Example #11
Source File: BannerExtension.tsx From crust-apps with Apache License 2.0 | 5 votes |
function BannerExtension (): React.ReactElement | null {
const { t } = useTranslation();
const { hasInjectedAccounts } = useApi();
const upgradableCount = useExtensionCounter();
const phishing = useRef<string>(t<string>('Since some extensions, such as the polkadot-js extension, protects you against all community reported phishing sites, there are valid reasons to use them for additional protection, even if you are not storing accounts in it.'));
if (!isSupported || !browserName) {
return null;
}
if (isWeb3Injected) {
if (hasInjectedAccounts) {
if (!upgradableCount) {
return null;
}
return (
<Banner type='warning'>
<p>{t<string>('You have {{upgradableCount}} extensions that need to be updated with the latest chain properties in order to display the correct information for the chain you are connected to. This update includes chain metadata and chain properties.', { replace: { upgradableCount } })}</p>
<p><Trans key='extensionUpgrade'>Visit your <a href='#/settings/metadata'>settings page</a> to apply the updates to the injected extensions.</Trans></p>
</Banner>
);
}
return (
<Banner type='warning'>
<p>{t<string>('One or more extensions are detected in your browser, however no accounts has been injected.')}</p>
<p>{t<string>('Ensure that the extension has accounts, some accounts are visible globally and available for this chain and that you gave the application permission to access accounts from the extension to use them.')}</p>
<p>{phishing.current}</p>
</Banner>
);
}
return (
<Banner type='warning'>
<p>{t<string>('It is recommended that you create/store your accounts securely and externally from the app. On {{yourBrowser}} the following browser extensions are available for use -', {
replace: {
yourBrowser: stringUpperFirst(browserName)
}
})}</p>
<ul>{availableExtensions[browserName].map(({ desc, link, name }): React.ReactNode => (
<li key={name}>
<a
href={link}
rel='noopener noreferrer'
target='_blank'
>
{name}
</a> ({t(desc)})
</li>
))
}</ul>
<p>{t<string>('Accounts injected from any of these extensions will appear in this application and be available for use. The above list is updated as more extensions with external signing capability become available.')} <a
href='https://github.com/polkadot-js/extension'
rel='noopener noreferrer'
target='_blank'
>{t<string>('Learn more...')}</a></p>
<p>{phishing.current}</p>
</Banner>
);
}
Example #12
Source File: ViewScore.tsx From longwave with MIT License | 5 votes |
export function ViewScore() {
const { t } = useTranslation();
const { gameState, clueGiver, spectrumCard } = useContext(GameModelContext);
if (!clueGiver) {
return null;
}
let score = GetScore(gameState.spectrumTarget, gameState.guess);
let bonusCoopTurn = false;
if (gameState.gameType === GameType.Cooperative && score === 4) {
score = 3;
bonusCoopTurn = true;
}
const wasCounterGuessCorrect =
(gameState.counterGuess === "left" &&
gameState.spectrumTarget < gameState.guess) ||
(gameState.counterGuess === "right" &&
gameState.spectrumTarget > gameState.guess);
return (
<div>
<Spectrum
spectrumCard={spectrumCard}
handleValue={gameState.guess}
targetValue={gameState.spectrumTarget}
/>
<CenteredColumn>
<div>
{t("viewscore.player_clue", { givername: clueGiver.name })}:{" "}
<strong>{gameState.clue}</strong>
</div>
<div>
{t("viewscore.score")}: {score} {t("viewscore.points")}!
</div>
{gameState.gameType === GameType.Teams && (
<div>
{TeamName(TeamReverse(clueGiver.team), t)} {t("viewscore.got")}{" "}
{wasCounterGuessCorrect
? t("viewscore.1_point_correct_guess")
: t("viewscore.0_point_wrong_guess")}
</div>
)}
{bonusCoopTurn && <Trans
i18nKey={t('viewscore.bonus_turn')}
components={{
strong: <strong />,
}}
/>}
<NextTurnOrEndGame />
</CenteredColumn>
</div>
);
}
Example #13
Source File: FeedbackForm.tsx From nosgestesclimat-site with MIT License | 5 votes |
export default function FeedbackForm({ onEnd, onCancel }: Props) {
// const tracker = useContext(TrackerContext)
const pathname = useLocation().pathname
const page = pathname.split('/').slice(-1)[0]
const isSimulateur = pathname.includes('simulateurs')
const lang = useTranslation().i18n.language
useEffect(() => {
const script = document.createElement('script')
script.src = 'https://code.jquery.com/jquery-2.1.4.min.js'
document.body.appendChild(script)
setTimeout(() => {
const script = document.createElement('script')
script.id = 'zammad_form_script'
script.async = true
script.onload = () => {
$('#feedback-form').ZammadForm({
messageTitle: `Remarque sur ${
isSimulateur ? 'le simulateur' : 'la page'
} ${page}`,
messageSubmit: 'Envoyer',
messageThankYou:
'Merci pour votre retour ! Vous pouvez aussi nous contacter directement à [email protected]',
lang,
attributes: [
{
display: 'Message',
name: 'body',
tag: 'textarea',
placeholder: 'Your Message...',
defaultValue: '',
rows: 7
},
{
display: 'Nom',
name: 'name',
tag: 'input',
type: 'text',
defaultValue: '-'
},
{
display: 'Email (pour recevoir notre réponse)',
name: 'email',
tag: 'input',
type: 'email',
placeholder: 'Your Email'
}
]
})
}
script.src = 'https://mon-entreprise.zammad.com/assets/form/form.js'
document.body.appendChild(script)
}, 100)
// tracker.push(['trackEvent', 'Feedback', 'written feedback submitted'])
}, [])
return (
<ScrollToElement onlyIfNotVisible>
<div style={{ textAlign: 'end' }}>
<button
onClick={() => onCancel()}
className="ui__ link-button"
style={{ textDecoration: 'none', marginLeft: '0.3rem' }}
aria-label="close"
>
X
</button>
</div>
<p>
<Trans i18nKey="feedback.bad.form.headline">
Votre retour nous est précieux afin d'améliorer ce site en continu.
Sur quoi devrions nous travailler afin de mieux répondre à vos
attentes ?
</Trans>
</p>
<div id="feedback-form"></div>
</ScrollToElement>
)
}
Example #14
Source File: EventsView.tsx From next-basics with GNU General Public License v3.0 | 5 votes |
export function EventsView(): React.ReactElement {
const { t } = useTranslation(NS_NEXT_BUILDER);
const { nodes } = useBuilderData();
const bricksWithEvents = getBricksWithEvents(nodes);
const [q, setQ] = React.useState<string>(null);
const hoverNodeUid = useHoverNodeUid();
const manager = useBuilderDataManager();
const handleSearch = React.useCallback((value: string): void => {
setQ(value);
}, []);
const filteredBricks = React.useMemo(
() => filterBricksWithEvents(bricksWithEvents, q),
[bricksWithEvents, q]
);
const handleMouseEnter = (uid: number): void => {
const prevUid = manager.getHoverNodeUid();
if (prevUid !== uid) {
manager.setHoverNodeUid(uid);
}
};
const handleMouseLeave = (uid: number): void => {
const prevUid = manager.getHoverNodeUid();
if (prevUid === uid) {
manager.setHoverNodeUid(undefined);
}
};
return (
<ToolboxPane
title={t(K.EVENTS)}
tooltips={
<>
<p>
<Trans t={t} i18nKey={K.EVENTS_VIEW_TIPS_1} />
</p>
<p>
<Trans t={t} i18nKey={K.EVENTS_VIEW_TIPS_2} />
</p>
</>
}
>
<SearchComponent
placeholder={t(K.SEARCH_BRICKS_WITH_EVENTS)}
onSearch={handleSearch}
/>
<div
className={`${styles.eventsWrapper} ${sharedStyles.customScrollbarContainer}`}
>
<ul className={styles.brickList}>
{filteredBricks.map((brick) => (
<li
key={brick.node.$$uid}
data-testid={`brick-with-events-item-${brick.node.$$uid}`}
onMouseEnter={() => handleMouseEnter(brick.node.$$uid)}
onMouseLeave={() => handleMouseLeave(brick.node.$$uid)}
>
<BrickWithEventsItem
{...brick}
hover={brick.node.$$uid === hoverNodeUid}
/>
</li>
))}
</ul>
</div>
</ToolboxPane>
);
}
Example #15
Source File: RemoveButton.tsx From tobira with Apache License 2.0 | 5 votes |
RemoveButton: React.FC<Props> = ({ block: blockRef, onConfirm }) => {
const { t } = useTranslation();
const block = useFragment(graphql`
fragment RemoveButtonData on Block {
id
}
`, blockRef);
const [commit] = useMutation<RemoveButtonMutation>(graphql`
mutation RemoveButtonMutation($id: ID!) {
removeBlock(id: $id) {
id @deleteRecord
realm {
... ContentManageRealmData
}
}
}
`);
const remove = () => {
commit({
variables: block,
onCompleted: () => {
currentRef(modalRef).done();
},
onError: error => {
currentRef(modalRef).reportError(
displayCommitError(error, t("manage.realm.content.removing-failed")),
);
},
});
};
const modalRef = useRef<ConfirmationModalHandle>(null);
return <>
<Button
title={t("manage.realm.content.remove")}
css={{
color: "var(--danger-color)",
"&&:hover": {
backgroundColor: "var(--danger-color)",
color: "var(--danger-color-bw-contrast)",
},
}}
onClick={() => {
currentRef(modalRef).open();
onConfirm?.();
}}
>
<FiTrash />
</Button>
<ConfirmationModal
buttonContent={t("manage.realm.content.remove")}
onSubmit={remove}
ref={modalRef}
>
<p>
<Trans i18nKey="manage.realm.danger-zone.delete.cannot-be-undone" />
</p>
</ConfirmationModal>
</>;
}
Example #16
Source File: ArtifactFilterDisplay.tsx From genshin-optimizer with MIT License | 5 votes |
export default function ArtifactFilterDisplay({ filterOption, filterOptionDispatch, }: { filterOption: FilterOption, filterOptionDispatch: (any) => void }) {
const { t } = useTranslation(["artifact", "ui"]);
const { artSetKeys = [], mainStatKeys = [], rarity = [], slotKeys = [], levelLow, levelHigh, substats = [],
location = "", exclusion = ["excluded", "included"], locked = ["locked", "unlocked"] } = filterOption
return <Grid container spacing={1}>
{/* left */}
<Grid item xs={12} md={6} display="flex" flexDirection="column" gap={1}>
{/* Artifact stars filter */}
<SolidToggleButtonGroup fullWidth onChange={(e, newVal) => filterOptionDispatch({ rarity: newVal })} value={rarity} size="small">
{allArtifactRarities.map(star => <ToggleButton key={star} value={star}><Stars stars={star} /></ToggleButton>)}
</SolidToggleButtonGroup>
{/* Artifact Slot */}
<SolidToggleButtonGroup fullWidth onChange={(e, newVal) => filterOptionDispatch({ slotKeys: newVal })} value={slotKeys} size="small">
{allSlotKeys.map(slotKey => <ToggleButton key={slotKey} value={slotKey}>{artifactSlotIcon(slotKey)}</ToggleButton>)}
</SolidToggleButtonGroup>
{/* exclusion + locked */}
<Box display="flex" gap={1}>
<SolidToggleButtonGroup fullWidth value={exclusion} onChange={(e, newVal) => filterOptionDispatch({ exclusion: newVal })} size="small">
<ToggleButton value="excluded" sx={{ display: "flex", gap: 1 }}>
<FontAwesomeIcon icon={faBan} /><Trans i18nKey={"exclusion.excluded"} t={t} />
</ToggleButton>
<ToggleButton value="included" sx={{ display: "flex", gap: 1 }}>
<FontAwesomeIcon icon={faChartLine} /><Trans i18nKey={"exclusion.included"} t={t} />
</ToggleButton>
</SolidToggleButtonGroup>
<SolidToggleButtonGroup fullWidth value={locked} onChange={(e, newVal) => filterOptionDispatch({ locked: newVal })} size="small">
<ToggleButton value="locked" sx={{ display: "flex", gap: 1 }}>
<Lock /><Trans i18nKey={"ui:locked"} t={t} />
</ToggleButton>
<ToggleButton value="unlocked" sx={{ display: "flex", gap: 1 }}>
<LockOpen /><Trans i18nKey={"ui:unlocked"} t={t} />
</ToggleButton>
</SolidToggleButtonGroup>
</Box>
{/* Artiface level filter */}
<ArtifactLevelSlider showLevelText levelLow={levelLow} levelHigh={levelHigh}
setLow={levelLow => filterOptionDispatch({ levelLow })}
setHigh={levelHigh => filterOptionDispatch({ levelHigh })}
setBoth={(levelLow, levelHigh) => filterOptionDispatch({ levelLow, levelHigh })} />
<Grid container display="flex" gap={1}>
<Grid item flexGrow={1}>
{/* location */}
<CharacterAutocomplete
value={location}
onChange={location => filterOptionDispatch({ location })}
placeholderText={t("artifact:filterLocation.any")}
defaultText={t("artifact:filterLocation.any")}
labelText={t("artifact:filterLocation.location")}
showDefault
showInventory
showEquipped
/>
</Grid>
</Grid>
</Grid>
{/* right */}
<Grid item xs={12} md={6} display="flex" flexDirection="column" gap={1}>
{/* Artifact Set */}
<ArtifactSetMultiAutocomplete artSetKeys={artSetKeys} setArtSetKeys={artSetKeys => filterOptionDispatch({ artSetKeys })} />
<ArtifactMainStatMultiAutocomplete mainStatKeys={mainStatKeys} setMainStatKeys={mainStatKeys => filterOptionDispatch({ mainStatKeys })} />
<ArtifactSubstatMultiAutocomplete substatKeys={substats} setSubstatKeys={substats => filterOptionDispatch({ substats })} />
</Grid>
</Grid>
}
Example #17
Source File: index.tsx From oasis-wallet-web with Apache License 2.0 | 5 votes |
export function ErrorFormatter(props: Props) {
const { t } = useTranslation()
const message = props.message
const errorMap: { [code in WalletErrors]: string | React.ReactElement } = {
[WalletErrors.UnknownError]: t('errors.unknown', 'Unknown error: {{message}}', { message }),
[WalletErrors.UnknownGrpcError]: t('errors.unknownGrpc', 'Unknown gRPC error: {{message}}', { message }),
[WalletErrors.InvalidAddress]: t('errors.invalidAddress', 'Invalid address'),
[WalletErrors.InvalidPrivateKey]: t('errors.invalidPrivateKey', 'Invalid private key'),
[WalletErrors.InsufficientBalance]: t('errors.insufficientBalance', 'Insufficient balance'),
[WalletErrors.CannotSendToSelf]: t('errors.cannotSendToSelf', 'Cannot send to yourself'),
[WalletErrors.InvalidNonce]: t('errors.invalidNonce', 'Invalid nonce (transaction number)'),
[WalletErrors.DuplicateTransaction]: t('errors.duplicateTransaction', 'Duplicate transaction'),
[WalletErrors.NoOpenWallet]: t('errors.noOpenWallet', 'No wallet opened'),
[WalletErrors.USBTransportNotSupported]: t(
'errors.usbTransportNotSupported',
'Your browser does not support WebUSB (e.g. Firefox). Try using Chrome.',
),
[WalletErrors.USBTransportError]: t('errors.usbTransportError', 'USB Transport error: {{message}}.', {
message,
}),
[WalletErrors.LedgerAppVersionNotSupported]: t(
'errors.ledgerAppVersionNotSupported',
'Oasis App on Ledger is closed or outdated. Make sure Ledger is unlocked, the Oasis App is opened and up to date.',
),
[WalletErrors.LedgerTransactionRejected]: t(
'errors.ledgerTransactionRejected',
'Transaction rejected on Ledger.',
),
[WalletErrors.LedgerNoDeviceSelected]: (
<Trans
i18nKey="errors.ledgerNoDeviceSelected"
t={t}
defaults="No Ledger device selected. Make sure it is connected, <0>check common USB connection issues with Ledger</0>, and <1>check site permissions don't block USB devices</1>."
components={[
<Anchor
href="https://support.ledger.com/hc/en-us/articles/115005165269-Fix-USB-connection-issues-with-Ledger-Live?support=true"
target="_blank"
rel="noopener"
/>,
<Anchor href="https://support.google.com/chrome/answer/114662" target="_blank" rel="noopener" />,
]}
/>
),
[WalletErrors.LedgerCannotOpenOasisApp]: t(
'errors.ledgerCannotOpenOasisApp',
'Could not open Oasis App on Ledger. Make sure Ledger is unlocked and the Oasis App is opened.',
),
[WalletErrors.LedgerOasisAppIsNotOpen]: t(
'errors.LedgerOasisAppIsNotOpen',
'Oasis App on Ledger is closed.',
),
[WalletErrors.LedgerUnknownError]: t('errors.unknownLedgerError', 'Unknown ledger error: {{message}}', {
message,
}),
}
const error = errorMap[props.code]
return <>{error}</>
}
Example #18
Source File: index.tsx From nanolooker with MIT License | 5 votes |
LanguagePreferences: React.FC<Props> = ({ isDetailed }) => {
const { t } = useTranslation();
return (
<Row style={{ alignItems: !isDetailed ? "center" : "flex-start" }}>
<Col xs={isDetailed ? 24 : undefined}>
<Text className={isDetailed ? "preference-detailed-title" : ""}>
{t("preferences.language")}
</Text>
</Col>
{isDetailed ? (
<Col xs={16}>
<Trans
i18nKey="preferences.languageDetailed"
style={{ marginLeft: "12px" }}
>
<a
href="https://github.com/running-coder/nanolooker/tree/master/src/i18n/locales"
rel="noopener noreferrer"
target="_blank"
>
{t("preferences.contribute")}
</a>
</Trans>
</Col>
) : null}
<Col
xs={isDetailed ? 8 : undefined}
style={{ textAlign: "right" }}
flex="auto"
>
<Select
value={i18next.language}
onChange={value => {
i18next.changeLanguage(value);
localStorage.setItem(LOCALSTORAGE_KEYS.LANGUAGE, value);
}}
style={{ width: 120 }}
>
<Option value="en">English</Option>
<Option value="fr">Français</Option>
<Option value="es">Español</Option>
<Option value="ar">العربية</Option>
<Option value="de">Deutsch</Option>
<Option value="fa">فارسی</Option>
<Option value="hi">हिन्दी</Option>
<Option value="it">Italiano</Option>
<Option value="ja">日本語</Option>
<Option value="ko">한국어</Option>
<Option value="nl">Nederlands</Option>
<Option value="pl">Polski</Option>
<Option value="pt">Português</Option>
<Option value="ru">Pусский</Option>
<Option value="tr">Türkçe</Option>
<Option value="vi">Tiếng Việt</Option>
<Option value="zh">中文</Option>
</Select>
</Col>
</Row>
);
}
Example #19
Source File: PaymentInfo.tsx From subscan-multisig-react with Apache License 2.0 | 5 votes |
function PaymentInfo({ accountId, className = '', extrinsic }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const [dispatchInfo, setDispatchInfo] = useState<RuntimeDispatchInfo | null>(null);
const balances = useCall<DeriveBalancesAll>(api.derive.balances?.all, [accountId]);
const mountedRef = useIsMountedRef();
useEffect((): void => {
accountId &&
extrinsic &&
isFunction(extrinsic.paymentInfo) &&
isFunction(api.rpc.payment?.queryInfo) &&
setTimeout((): void => {
try {
extrinsic
.paymentInfo(accountId)
.then((info) => mountedRef.current && setDispatchInfo(info))
.catch(console.error);
} catch (error) {
console.error(error);
}
}, 0);
}, [api, accountId, extrinsic, mountedRef]);
if (!dispatchInfo || !extrinsic) {
return null;
}
const isFeeError =
api.consts.balances &&
!api.tx.balances?.transfer.is(extrinsic) &&
balances?.accountId.eq(accountId) &&
(balances.availableBalance.lte(dispatchInfo.partialFee) ||
balances.freeBalance.sub(dispatchInfo.partialFee).lte(api.consts.balances.existentialDeposit as unknown as BN));
return (
<>
<Expander
className={className}
summary={
<Trans i18nKey="feesForSubmission">
Fees of <span className="highlight">{formatBalance(dispatchInfo.partialFee, { withSiFull: true })}</span>{' '}
will be applied to the submission
</Trans>
}
/>
{isFeeError && (
<MarkWarning
content={t<string>(
'The account does not have enough free funds (excluding locked/bonded/reserved) available to cover the transaction fees without dropping the balance below the account existential amount.'
)}
/>
)}
</>
);
}
Example #20
Source File: About.tsx From TidGi-Desktop with Mozilla Public License 2.0 | 5 votes |
export default function About(): JSX.Element {
const { t } = useTranslation();
const versions = usePromiseValue(async () => {
const processVersions = await window.service.context.get('environmentVersions');
return [
{ name: 'Electron Version', version: processVersions.electron },
{ name: 'Node Version', version: processVersions.node },
{ name: 'Chromium Version', version: processVersions.chrome },
];
}, [] as Array<{ name: string; version: string }>);
const appVersion = usePromiseValue<string>(async () => await window.service.context.get('appVersion'));
const platform = usePromiseValue<string>(async () => await window.service.context.get('platform'));
return (
<DialogContent>
<div id="test" data-usage="For spectron automating testing" />
<Helmet>
<title>{t('ContextMenu.About')}</title>
</Helmet>
<Icon src={iconPath} alt="TidGi" />
<Title>TidGi ({platform ?? 'Unknown Platform'})</Title>
<TidGiVersion>{`Version v${appVersion ?? ' - '}.`}</TidGiVersion>
<DependenciesVersionsContainer>
{versions?.map(({ name, version }) => (
<DependenciesVersions key={name}>
{name}: {version}
</DependenciesVersions>
))}
</DependenciesVersionsContainer>
<ButtonContainer>
<GoToTheWebsiteButton onClick={async () => await window.service.native.open('https://github.com/tiddly-gittly/TidGi-Desktop')}>
Website
</GoToTheWebsiteButton>
<GoToTheWebsiteButton onClick={async () => await window.service.native.open('https://github.com/tiddly-gittly/TidGi-Desktop/issues/new/choose')}>
Support
</GoToTheWebsiteButton>
</ButtonContainer>
<MadeBy>
<Trans t={t} i18nKey="Dialog.MadeWithLove">
<span>Made with </span>
<span role="img" aria-label="love">
❤
</span>
<span> by </span>
</Trans>
<Link
onClick={async () => await window.service.native.open('https://onetwo.ren/wiki/')}
onKeyDown={async (event) => {
if (event.key !== 'Enter') {
return;
}
await window.service.native.open('https://onetwo.ren/wiki/');
}}
role="link"
tabIndex={0}>
{t('LinOnetwo')}
</Link>
<span> && </span>
<Link
onClick={async () => await window.service.native.open('https://webcatalog.app/?utm_source=tidgi_app')}
onKeyDown={async (event) => {
if (event.key !== 'Enter') {
return;
}
await window.service.native.open('https://webcatalog.app/?utm_source=tidgi_app');
}}
role="link"
tabIndex={0}>
{t('Preference.WebCatalog')}
</Link>
</MadeBy>
</DialogContent>
);
}
Example #21
Source File: ConvertQUICKPage.tsx From interface-v2 with GNU General Public License v3.0 | 4 votes |
ConvertQUICKPage: React.FC = () => {
const classes = useStyles();
const { t } = useTranslation();
const { account, library } = useActiveWeb3React();
const [quickAmount, setQUICKAmount] = useState('');
const [quickV2Amount, setQUICKV2Amount] = useState('');
const [approving, setApproving] = useState(false);
const [attemptConverting, setAttemptConverting] = useState(false);
const [showConfirm, setShowConfirm] = useState(false);
const [txPending, setTxPending] = useState(false);
const [txHash, setTxHash] = useState('');
const [txError, setTxError] = useState('');
const quickToken = returnTokenFromKey('QUICK');
const quickBalance = useTokenBalance(account ?? undefined, quickToken);
const quickConvertContract = useQUICKConversionContract();
const parsedAmount = tryParseAmount(quickAmount, quickToken);
const [approval, approveCallback] = useApproveCallback(
parsedAmount,
quickConvertContract?.address,
);
const quickConvertingText = t('convertingQUICKtoQUICKV2', {
quickAmount,
quickV2Amount,
});
const quickConvertedText = t('convertedQUICKtoQUICKV2', {
quickAmount,
quickV2Amount,
});
const txSubmittedQuickConvertText = t('submittedTxQUICKConvert', {
quickAmount,
quickV2Amount,
});
const successQuickConvertedText = t('successConvertedQUICKtoQUICKV2', {
quickAmount,
quickV2Amount,
});
const isInsufficientQUICK =
Number(quickAmount) > Number(quickBalance?.toExact() ?? 0);
const buttonText = useMemo(() => {
if (!quickAmount || !Number(quickAmount)) {
return t('enterAmount');
} else if (approval !== ApprovalState.APPROVED) {
return t('approve');
} else if (isInsufficientQUICK) {
return t('insufficientBalance');
} else {
return t('convert');
}
}, [isInsufficientQUICK, quickAmount, t, approval]);
const addTransaction = useTransactionAdder();
const finalizedTransaction = useTransactionFinalizer();
const handleDismissConfirmation = () => {
setShowConfirm(false);
};
const attemptToApprove = async () => {
setApproving(true);
try {
await approveCallback();
setApproving(false);
} catch (e) {
setApproving(false);
}
};
const convertQUICK = async () => {
if (quickConvertContract && library && parsedAmount) {
setAttemptConverting(true);
setShowConfirm(true);
await quickConvertContract
.quickToQuickX(parsedAmount.raw.toString(), {
gasLimit: 300000,
})
.then(async (response: TransactionResponse) => {
setAttemptConverting(false);
setTxPending(true);
setTxError('');
setTxHash('');
addTransaction(response, {
summary: quickConvertingText,
});
try {
const tx = await response.wait();
finalizedTransaction(tx, {
summary: quickConvertedText,
});
setTxPending(false);
setTxHash(tx.transactionHash);
} catch (err) {
setTxPending(false);
setTxError(t('errorInTx'));
}
})
.catch(() => {
setAttemptConverting(false);
setTxPending(false);
setTxHash('');
setTxError(t('txRejected'));
});
}
};
return (
<Box width='100%' maxWidth={488} id='convertQUICKPage'>
<Typography variant='h4'>{t('convert')} QUICK</Typography>
<Box className={classes.wrapper}>
<Box display='flex' alignItems='center' mb={3}>
<Box className={classes.iconWrapper}>
<img src={QUICKIcon} alt='QUICK' />
</Box>
<Typography variant='h6'>QUICK(OLD)</Typography>
<Box mx={1.5} className={classes.convertArrow}>
<ArrowForward />
</Box>
<Box className={classes.iconWrapper}>
<QUICKV2Icon />
</Box>
<Typography variant='h6'>QUICK(NEW)</Typography>
</Box>
<Typography variant='body2' color='textSecondary'>
<Trans i18nKey='convertQuick'>
Convert your QUICK(OLD) to QUICK(NEW). Read more about QUICK token
split{' '}
<a
href='https://quickswap-layer2.medium.com/you-voted-for-a-1-1000-token-split-to-make-quick-more-appealing-9c25c2a2dd7e'
rel='noreferrer'
target='_blank'
>
here
</a>
</Trans>
</Typography>
<Box className={classes.conversionRate}>
<Typography variant='caption'>
{t('conversionRate')}: 1 QUICK(OLD) ={' '}
{GlobalConst.utils.QUICK_CONVERSION_RATE} QUICK(NEW)
</Typography>
</Box>
<Box mt={4} mb={2}>
<Typography variant='body2' color='textSecondary'>
{t('yourbalance')}: {formatTokenAmount(quickBalance)}
</Typography>
<Box
className={cx(
classes.currencyInput,
isInsufficientQUICK && classes.errorInput,
)}
>
<NumericalInput
placeholder='0.00'
value={quickAmount}
fontSize={18}
onUserInput={(value) => {
const digits =
value.indexOf('.') > -1 ? value.split('.')[1].length : 0;
let fixedVal = value;
if (digits > quickToken.decimals) {
fixedVal = Number(value).toFixed(quickToken.decimals);
}
setQUICKAmount(fixedVal);
setQUICKV2Amount(
(
Number(fixedVal) * GlobalConst.utils.QUICK_CONVERSION_RATE
).toLocaleString('fullwide', {
useGrouping: false,
maximumFractionDigits: quickToken.decimals,
}),
);
}}
/>
<Box
mr={1}
className={classes.maxButton}
onClick={() => {
if (quickBalance) {
setQUICKAmount(quickBalance.toExact());
setQUICKV2Amount(
(
Number(quickBalance.toExact()) *
GlobalConst.utils.QUICK_CONVERSION_RATE
).toString(),
);
}
}}
>
{t('max')}
</Box>
<Typography variant='h6'>QUICK(OLD)</Typography>
</Box>
{isInsufficientQUICK && (
<Typography variant='body2' className={classes.errorText}>
{t('insufficientBalance', { symbol: 'QUICK' })}
</Typography>
)}
</Box>
<Box ml={2} className={classes.convertArrow}>
<ArrowDownward />
</Box>
<Box mt={2} mb={4}>
<Typography variant='body2' color='textSecondary'>
{t('youwillreceive')}:
</Typography>
<Box className={classes.currencyInput}>
<NumericalInput
placeholder='0.00'
value={quickV2Amount}
fontSize={18}
onUserInput={(value) => {
setQUICKV2Amount(value);
const quickAmount = (
Number(value) / GlobalConst.utils.QUICK_CONVERSION_RATE
).toLocaleString('fullwide', {
useGrouping: false,
maximumFractionDigits: quickToken.decimals,
});
setQUICKAmount(quickAmount);
}}
/>
<Typography variant='h6'>QUICK(NEW)</Typography>
</Box>
</Box>
<Box display='flex' justifyContent='center'>
<Button
disabled={
approving ||
attemptConverting ||
isInsufficientQUICK ||
!quickAmount ||
!Number(quickAmount)
}
className={classes.convertButton}
onClick={() => {
if (approval === ApprovalState.APPROVED) {
convertQUICK();
} else {
attemptToApprove();
}
}}
>
{buttonText}
</Button>
</Box>
</Box>
{showConfirm && (
<TransactionConfirmationModal
isOpen={showConfirm}
onDismiss={handleDismissConfirmation}
attemptingTxn={attemptConverting}
txPending={txPending}
hash={txHash}
content={() =>
txError ? (
<TransactionErrorContent
onDismiss={handleDismissConfirmation}
message={txError}
/>
) : (
<ConfirmationModalContent
title={t('convertingQUICK')}
onDismiss={handleDismissConfirmation}
content={() => (
<Box textAlign='center'>
<Box mt={6} mb={5}>
<CircularProgress size={80} />
</Box>
<Typography variant='body1'>
{quickConvertingText}
</Typography>
</Box>
)}
/>
)
}
pendingText={quickConvertingText}
modalContent={
txPending ? txSubmittedQuickConvertText : successQuickConvertedText
}
/>
)}
</Box>
);
}
Example #22
Source File: SubmissionForm.tsx From fishbowl with MIT License | 4 votes |
function SubmissionForm(props: { onSubmit: () => void }) {
const { t } = useTranslation()
const currentPlayer = React.useContext(CurrentPlayerContext)
const currentGame = React.useContext(CurrentGameContext)
const [submitCards, { called }] = useSubmitCardsMutation()
const numSubmitted = filter(
currentGame.cards,
(card) => card.player_id === currentPlayer.id
).length
const numToSubmit =
(currentGame.num_entries_per_player &&
currentGame.num_entries_per_player - numSubmitted) ||
0
const [words, setWords] = React.useState<Array<string>>(
Array.from(
{
length: numToSubmit,
},
() => ""
)
)
React.useEffect(() => {
setWords(
Array.from(
{
length: numToSubmit,
},
() => ""
)
)
}, [numToSubmit])
const emptyWords = words.some((word) => word.length < 1)
return (
<>
<Grid item>
<Title
text={t("cardSubmission.title", "Submit {{ count }} card", {
count: numToSubmit,
defaultValue_plural: "Submit {{ count }} cards",
})}
/>
</Grid>
<Grid item>
{t(
"cardSubmission.description",
'These cards will be put into the "fishbowl," and drawn randomly in rounds of {{ rounds }}. They can be words, familiar phrases, or inside jokes!',
{
rounds: currentGame.rounds
.map((round) => startCase(round.value))
.join(", "),
}
)}
</Grid>
{currentGame.starting_letter && (
<Grid item>
<Trans t={t} i18nKey="cardSubmission.descriptionLetter">
{"They must start with the letter "}
<b>{{ letter: currentGame.starting_letter.toLocaleUpperCase() }}</b>
.
</Trans>
</Grid>
)}
<Grid item container direction="column" spacing={2} alignItems="center">
{words.map((_, index) => {
return (
<Grid item key={index}>
<SubmissionCard
onChange={(value: string) => {
const newWords = cloneDeep(words)
newWords[index] = value
setWords(newWords)
}}
word={words[index]}
/>
</Grid>
)
})}
</Grid>
<Grid item>
<Button
variant="contained"
color="primary"
size="large"
disabled={called || emptyWords}
onClick={async () => {
await submitCards({
variables: {
cards: words.map((word) => {
return {
player_id: currentPlayer.id,
game_id: currentGame.id,
word: word,
}
}),
},
})
props.onSubmit()
}}
>
{t("cardSubmission.submitButton", "Submit")}
</Button>
</Grid>
</>
)
}
Example #23
Source File: header.component.tsx From cwa-quick-test-frontend with Apache License 2.0 | 4 votes |
Header = (props: any) => {
const navigation = useNavigation();
const history = useHistory();
const { t } = useTranslation();
const { keycloak } = useKeycloak();
const [userName, setUserName] = React.useState('');
const [isInit, setIsInit] = React.useState(false)
const [environmentName] = useLocalStorage('environmentName', '');
React.useEffect(() => {
if (navigation)
setIsInit(true);
}, [navigation])
// set user name from keycloak
React.useEffect(() => {
if (keycloak.idTokenParsed) {
setUserName((keycloak.idTokenParsed as any).name);
}
}, [keycloak])
const handleLogout = () => {
keycloak.logout({ redirectUri: window.location.origin + navigation!.calculatedRoutes.landing });
}
const changePasswordUrl = keycloak.authServerUrl + 'realms/' + keycloak.realm + '/account/password';
return (!isInit ? <></> :
<Container className='position-relative'>
{/* simple header with logo */}
{/* user icon and user name */}
<Row id='qt-header'>
<Image id='c19-logo' src={C19Logo} />
<span className='header-font my-auto mx-1 pt-1'>
{t('translation:title')}
{!environmentName
? <></>
: <span className='environment-font my-auto mx-1'>
{'\n' + environmentName}
</span>
}
</span>
{!(environmentName && history.location.pathname === navigation?.routes.root)
? <></>
: < span className='environment-info-text py-3'>
<Trans>
{t('translation:environment-info1')}
{<a
href={t('translation:environment-info-link')}
target='blank'
>
{t('translation:environment-info-link')}
</a>}
{'.'}
</Trans>
</span>
}
</Row>
{/* {!environmentName
? <></>
: <Row id='qt-environment'>
<span className='header-font my-auto mx-1'>
{environmentName}
</span>
</Row>
} */}
<Navbar id='user-container' >
<NavDropdown
className="nav-dropdown-title"
title={userName}
id="responsive-navbar-nav"
>
<Nav.Link
className='mx-0 dropdown-item'
onClick={handleLogout}
>
{t('translation:logout')}
</Nav.Link>
<NavDropdown.Divider className='m-0' />
<Nav.Link className='mx-0 dropdown-item' href={changePasswordUrl} target='passwordchange'>
{t('translation:change-password')}
</Nav.Link>
</NavDropdown>
</Navbar>
</Container >
)
}
Example #24
Source File: index.tsx From crust-apps with Apache License 2.0 | 4 votes |
function MaxwellClaims (): React.ReactElement<Props> { const [didCopy, setDidCopy] = useState(false); const [ethereumAddress, setEthereumAddress] = useState<string | undefined | null>(null); const [signature, setSignature] = useState<EcdsaSignature | null>(null); const [step, setStep] = useState<Step>(Step.Account); const [accountId, setAccountId] = useState<string | null>(null); const { api, systemChain } = useApi(); const { t } = useTranslation(); const [statusOpen, setStatusOpen] = useState<boolean>(false); const [result, setResult] = useState<string>(''); const [status, setStatus] = useState<string>(''); const [ethereumTxHashValid, setEthereumTxHashValid] = useState<boolean>(false); const [isBusy, setIsBusy] = useState<boolean>(false); const [isValid, setIsValid] = useState(false); const [ethereumTxHash, setEthereumTxHash] = useState<string | undefined | null>(null); // This preclaimEthereumAddress holds the result of `api.query.claims.preclaims`: // - an `EthereumAddress` when there's a preclaim // - null if no preclaim // - `PRECLAIMS_LOADING` if we're fetching the results const [preclaimEthereumAddress, setPreclaimEthereumAddress] = useState<string | null | undefined | typeof PRECLAIMS_LOADING>(PRECLAIMS_LOADING); const isPreclaimed = !!preclaimEthereumAddress && preclaimEthereumAddress !== PRECLAIMS_LOADING; const claimLimit = useCall<BalanceOf>(api.query.claims.claimLimit); // Everytime we change account, reset everything, and check if the accountId // has a preclaim. useEffect(() => { if (!accountId) { return; } setStep(Step.Account); setEthereumAddress(null); setEthereumTxHash(null); setPreclaimEthereumAddress(PRECLAIMS_LOADING); if (!api.query.claims || !api.query.claims.preclaims) { return setPreclaimEthereumAddress(null); } api.query.claims .preclaims<Option<EthereumAddress>>(accountId) .then((preclaim): void => { const address = preclaim.unwrapOr(null)?.toString(); setEthereumAddress(address); setPreclaimEthereumAddress(address); }) .catch((): void => setPreclaimEthereumAddress(null)); }, [accountId, api.query.claims, api.query.claims.preclaims]); // Old claim process used `api.tx.claims.claim`, and didn't have attest const isOldClaimProcess = !api.tx.claims.claimAttest; useEffect(() => { if (didCopy) { setTimeout((): void => { setDidCopy(false); }, 1000); } }, [didCopy]); const goToStepAccount = useCallback(() => { setStep(Step.Account); setEthereumTxHash(""); setEthereumTxHashValid(false); }, []); const goToStepSign = useCallback(() => { setStep(Step.Sign); }, []); const goToStepClaim = useCallback(() => { setStep(Step.Claim); }, []); const handleAccountStep = useCallback(async () => { setIsBusy(true); const result = await httpPost("https://bridge-api.crust.network/claim/" + ethereumTxHash); setIsBusy(false); setResult(result.statusText); setStatus(result.status); if (result.code == 200) { setStatusOpen(true); setEthereumTxHashValid(true); goToStepSign(); } else { api.query.claims .claims<Option<BalanceOf>>(ethereumTxHash?.toString()) .then((claim): void => { const claimOpt = JSON.parse(JSON.stringify(claim)); if (claimOpt) { api.query.claims .claimed<Option<BalanceOf>>(ethereumTxHash?.toString()) .then((claimed): void => { const isClaimed = JSON.parse(JSON.stringify(claimed)); if (isClaimed) { setStatusOpen(true); } else { setStatusOpen(true); setResult('MintClaimSuccess'); setStatus('success'); setEthereumTxHashValid(true); goToStepSign(); } }); } else { setStatusOpen(true); } }) .catch((): void => setIsBusy(false)); } }, [ethereumAddress, goToStepClaim, goToStepSign, isPreclaimed, isOldClaimProcess, ethereumTxHash]); const onChangeEthereumTxHash = useCallback((hex: string) => { let [isValid, value] = convertInput(hex); isValid = isValid && ( length !== -1 ? value.length === 32 : value.length !== 0 ); setIsValid(isValid); setEthereumTxHash(hex.trim()); }, [ethereumTxHash]); function convertInput (value: string): [boolean, Uint8Array] { if (value === '0x') { return [true, new Uint8Array([])]; } else if (value.startsWith('0x')) { try { return [true, hexToU8a(value)]; } catch (error) { return [false, new Uint8Array([])]; } } // maybe it is an ss58? try { return [true, decodeAddress(value)]; } catch (error) { // we continue } return isAscii(value) ? [true, stringToU8a(value)] : [value === '0x', new Uint8Array([])]; } // Depending on the account, decide which step to show. // const handleAccountStep = useCallback(() => { // if (isPreclaimed) { // goToStepClaim(); // } else if (ethereumAddress || isOldClaimProcess) { // goToStepSign(); // } else { // setStep(Step.ETHAddress); // } // }, [ethereumAddress, goToStepClaim, goToStepSign, isPreclaimed, isOldClaimProcess]); const onChangeSignature = useCallback((event: React.SyntheticEvent<Element>) => { const { value: signatureJson } = event.target as HTMLInputElement; const { ethereumAddress, signature } = recoverFromJSON(signatureJson); setEthereumAddress(ethereumAddress?.toString()); setSignature(signature); }, []); const onChangeEthereumAddress = useCallback((value: string) => { // FIXME We surely need a better check than just a trim setEthereumAddress(value.trim()); }, []); const onCopy = useCallback(() => { setDidCopy(true); }, []); // If it's 1/ not preclaimed and 2/ not the old claiming process, fetch the // statement kind to sign. const statementKind = useCall<StatementKind | null>(!isPreclaimed && !isOldClaimProcess && !!ethereumAddress && api.query.claims.signing, [ethereumAddress], transformStatement); const statementSentence = getStatement(systemChain, statementKind)?.sentence || ''; const prefix = u8aToString(api.consts.claims.prefix.toU8a(true)); const payload = accountId ? `${prefix}${u8aToHex(decodeAddress(accountId), -1, false)}${statementSentence}${ethereumTxHash?.substring(2)}` : ''; return ( <main> {!isOldClaimProcess && <Warning />} <h1> <Trans>Claim your <em>{TokenUnit.abbr}</em> tokens</Trans> </h1> <Columar> <Columar.Column> <Card withBottomMargin> <h3><span style={{"wordWrap": "break-word", "wordBreak": "break-all"}}>{t<string>(`0. Please make sure you have the authority to make signature with the private key of the wallet account `)}<span style={{ 'fontWeight': 'bold' }}>({t<string>('address: ')}<a href='https://etherscan.io/address/0x17a9037cdfb24ffcc13697d03c3bcd4dff34732b' target="_blank">0x17A9037cdFB24FfcC13697d03C3bcd4DFF34732b</a>)</span><span>{t<string>(', using an exchange account to sent a transfer (withdrawal) transaction will be invalidated and cause asset loss.')}</span> <span style={{ 'fontWeight': 'bold', 'color': 'red' }}>{t<string>(` This is Maxwell's claim. If you want to claim your tokens to the mainnet, please click on the upper left corner to switch to the mainnet, You are responsible for the consequences!`)}</span></span></h3> <img style={{'marginLeft': 'auto', 'marginRight': 'auto', 'display': 'block', "width": "150px" }} src={claimPng as string} /> </Card> {(<Card withBottomMargin> <h3>{t<string>(`1. Select your {{chain}} account and enter`, { replace: { chain: systemChain } })} <a href='https://etherscan.io/token/0x32a7C02e79c4ea1008dD6564b35F131428673c41'>{t('ERC20 CRU')}</a> {t<string>('transfer tx hash')}, <span>{t<string>(`The remaining claim limit is `)}<span style={{'color': '#ff8812', 'textDecoration': 'underline', 'fontStyle': 'italic'}}>{formatBalance(claimLimit, { withUnit: 'CRU' })}</span><span>{t<string>(`, If your claim amount is greater than the claim limit, please wait for the limit update`)}</span></span> </h3> <InputAddress defaultValue={accountId} help={t<string>('The account you want to claim to.')} isDisabled={ethereumTxHashValid} label={t<string>('claim to account')} onChange={setAccountId} type='account' /> <Input autoFocus className='full' help={t<string>('The Ethereum CRU transfer tx hash (starting by "0x")')} isDisabled={ethereumTxHashValid} isError={!isValid} label={t<string>('Ethereum tx hash')} onChange={onChangeEthereumTxHash} placeholder={t<string>('0x prefixed hex, e.g. 0x1234 or ascii data')} value={ethereumTxHash || ''} /> {(step === Step.Account) && (<Button.Group> <Button icon='sign-in-alt' isBusy={isBusy} isDisabled={preclaimEthereumAddress === PRECLAIMS_LOADING || ethereumTxHash === null || ethereumTxHash === '' || !isValid} label={preclaimEthereumAddress === PRECLAIMS_LOADING ? t<string>('Loading') : t<string>('Continue') } onClick={handleAccountStep} /> </Button.Group>)} <HttpStatus isStatusOpen={statusOpen} message={result} setStatusOpen={setStatusOpen} status={status} /> </Card>)} { // We need to know the ethereuem address only for the new process // to be able to know the statement kind so that the users can sign it (step >= Step.ETHAddress && !isPreclaimed && !isOldClaimProcess) && ( <Card withBottomMargin> <h3>{t<string>('2. Enter the ETH address from the sale.')}</h3> <Input autoFocus className='full' help={t<string>('The the Ethereum address you used during the pre-sale (starting by "0x")')} label={t<string>('Pre-sale ethereum address')} onChange={onChangeEthereumAddress} value={ethereumAddress || ''} /> {(step === Step.ETHAddress) && ( <Button.Group> <Button icon='sign-in-alt' isDisabled={!ethereumAddress} label={t<string>('Continue')} onClick={goToStepSign} /> </Button.Group> )} </Card> )} {(step >= Step.Sign && !isPreclaimed) && ( <Card> <h3>{t<string>('{{step}}. Sign with your ETH address', { replace: { step: isOldClaimProcess ? '2' : '3' } })}</h3> {!isOldClaimProcess && ( <Statement kind={statementKind} systemChain={systemChain} /> )} <div>{t<string>('Copy the following string and sign it with the Ethereum account you used during the pre-sale in the wallet of your choice, using the string as the payload, and then paste the transaction signature object below:')}</div> <CopyToClipboard onCopy={onCopy} text={payload} > <Payload data-for='tx-payload' data-tip > {payload} </Payload> </CopyToClipboard> <Tooltip place='right' text={didCopy ? t<string>('copied') : t<string>('click to copy')} trigger='tx-payload' /> <div>{t<string>('Paste the signed message into the field below. The placeholder text is there as a hint to what the message should look like:')}</div> <Signature onChange={onChangeSignature} placeholder={`{\n "address": "0x ...",\n "msg": "${prefix}...",\n "sig": "0x ...",\n "version": "3",\n "signer": "..."\n}`} rows={10} /> {(step === Step.Sign) && ( <Button.Group> <Button icon='sign-in-alt' isDisabled={!accountId || !signature} label={t<string>('Confirm claim')} onClick={goToStepClaim} /> </Button.Group> )} </Card> )} </Columar.Column> <Columar.Column> {(step >= Step.Claim) && ( isPreclaimed ? <AttestDisplay accountId={accountId} ethereumAddress={ethereumAddress} onSuccess={goToStepAccount} statementKind={statementKind} systemChain={systemChain} /> : <ClaimDisplay accountId={accountId} ethereumAddress={ethereumAddress} ethereumSignature={signature} isOldClaimProcess={isOldClaimProcess} onSuccess={goToStepAccount} statementKind={statementKind} ethereumTxHash={ethereumTxHash} /> )} </Columar.Column> </Columar> </main> ); }
Example #25
Source File: PageFeedback.tsx From nosgestesclimat-site with MIT License | 4 votes |
export default function PageFeedback({
customMessage,
customEventName
}: PageFeedbackProps) {
const location = useLocation()
const tracker = useContext(TrackerContext)
const [state, setState] = useState({
showForm: false,
showThanks: false,
feedbackAlreadyGiven: feedbackAlreadyGiven([
customEventName || 'rate page usefulness',
location.pathname
])
})
const handleFeedback = useCallback(({ useful }: { useful: boolean }) => {
tracker.push([
'trackEvent',
'Feedback',
useful ? 'positive rating' : 'negative rating',
location.pathname
])
const feedback = [
customEventName || 'rate page usefulness',
location.pathname,
useful ? 10 : 0.1
] as [string, string, number]
tracker.push(['trackEvent', 'Feedback', ...feedback])
saveFeedbackOccurrenceInLocalStorage(feedback)
setState({
showThanks: useful,
feedbackAlreadyGiven: true,
showForm: !useful
})
}, [])
const handleErrorReporting = useCallback(() => {
tracker.push(['trackEvent', 'Feedback', 'report error', location.pathname])
setState({ ...state, showForm: true })
}, [])
if (state.feedbackAlreadyGiven && !state.showForm && !state.showThanks) {
return null
}
return (
<div
className="ui__ container"
style={{ display: 'flex', justifyContent: 'center' }}
>
<div className="feedback-page ui__ notice ">
{!state.showForm && !state.showThanks && (
<>
<div style={{ flexShrink: 0 }}>
{customMessage || (
<Trans i18nKey="feedback.question">
Cette page vous est utile ?
</Trans>
)}{' '}
</div>
<div className="feedbackButtons">
<button
className="ui__ link-button"
onClick={() => handleFeedback({ useful: true })}
>
<Trans>Oui</Trans>
</button>{' '}
<button
className="ui__ link-button"
onClick={() => handleFeedback({ useful: false })}
>
<Trans>Non</Trans>
</button>
<button
className="ui__ link-button"
onClick={handleErrorReporting}
>
<Trans i18nKey="feedback.reportError">
Faire une suggestion
</Trans>
</button>
</div>
</>
)}
{state.showThanks && (
<div>
<Trans i18nKey="feedback.thanks">
Merci pour votre retour ! Vous pouvez nous contacter directement à{' '}
<a href="mailto:[email protected]">
[email protected]
</a>
</Trans>
</div>
)}
{state.showForm && (
<Form
onEnd={() =>
setState({ ...state, showThanks: true, showForm: false })
}
onCancel={() =>
setState({ ...state, showThanks: false, showForm: false })
}
/>
)}
</div>
</div>
)
}
Example #26
Source File: index.tsx From rocketredis with MIT License | 4 votes |
DeleteConnectionModal: React.FC<ConnectionModalProps> = ({
visible,
onRequestClose,
connectionToDelete
}) => {
const formRef = useRef<FormHandles>(null)
const { t } = useTranslation('deleteConnection')
const { addToast } = useToast()
const setConnections = useSetRecoilState(connectionsState)
const [deleteConnectionLoading, toggleDeleteConnectionLoading] = useToggle(
false
)
const handleCloseModal = useCallback(() => {
if (onRequestClose) {
onRequestClose()
}
}, [onRequestClose])
const handleDeleteConnection = useCallback(
async ({ confirmation: deleteConfirmation }: DeleteConnectionFormData) => {
try {
toggleDeleteConnectionLoading()
formRef.current?.setErrors({})
if (deleteConfirmation !== 'DELETE') {
formRef.current?.setErrors({
confirmation: t('form.unconfirmedDeletionError')
})
return
}
const connections = deleteAndGetConnections(connectionToDelete)
setConnections(connections)
addToast({
type: 'success',
title: 'Connection deleted',
description: 'This connection will not be available anymore.'
})
handleCloseModal()
} catch (error) {
addToast({
type: 'error',
title: 'Error deleting connection',
description: error.message || 'Unexpected error occurred, try again.'
})
} finally {
toggleDeleteConnectionLoading()
}
},
[
toggleDeleteConnectionLoading,
t,
addToast,
connectionToDelete,
setConnections,
handleCloseModal
]
)
return (
<Modal visible={visible} onRequestClose={onRequestClose}>
<h1>{t('title')}</h1>
<TextContent>
<p>
<Trans
t={t}
i18nKey="deletingConnectionMessage"
values={{ name: connectionToDelete.name }}
>
The connection <strong>{name}</strong> will be permanently deleted.
</Trans>
</p>
<p>
<Trans t={t} i18nKey="confirmDeletionMessage" />
</p>
</TextContent>
<Form ref={formRef} onSubmit={handleDeleteConnection}>
<Input name="confirmation" />
<ActionsContainer>
<ButtonGroup>
<Button onClick={handleCloseModal} type="button" color="opaque">
{t('form.cancel')}
</Button>
<Button loading={deleteConnectionLoading} type="submit" color="red">
<FiTrash />
{t('form.confirmDeletion')}
</Button>
</ButtonGroup>
</ActionsContainer>
</Form>
</Modal>
)
}
Example #27
Source File: DataView.tsx From next-basics with GNU General Public License v3.0 | 4 votes |
export function DataView({
onContextUpdate,
}: DataViewProps): React.ReactElement {
const { nodes } = useBuilderData();
const { t } = useTranslation(NS_NEXT_BUILDER);
const rootNode = useBuilderNode({ isRoot: true });
const contextWithUniqueSymbolId: ContextConfWithSymbolId[] = useMemo(() => {
const originContext = ((rootNode?.context as ContextConf[]) ?? []).map(
(v) => ({
...v,
[symbolId]: uniqueId(),
})
);
return originContext;
}, [rootNode?.context]);
const [settingItemForm] = Form.useForm();
const [q, setQ] = useState<string>("");
const [visible, setVisible] = useState<boolean>(false);
const [settingItem, setSettingItem] = useState<ContextConf>();
const settingUid = useRef<string | undefined>();
const [hoverContextName, setHoverContextName] = useState<string>();
const manager = useBuilderDataManager();
const [highlightedContexts, setHighlightedContexts] = useState(
new Set<string>()
);
const handleSearch = (value: string): void => {
setQ(value);
};
const filteredContextList: ContextConfWithSymbolId[] = useMemo(
() => deepFilter(contextWithUniqueSymbolId, q),
[contextWithUniqueSymbolId, q]
);
useEffect(() => {
const nodesToHighlight = new Set<number>();
if (hoverContextName) {
nodes.forEach((node) => {
if (scanContextsInAny(node.$$normalized).includes(hoverContextName)) {
nodesToHighlight.add(node.$$uid);
}
});
}
manager.setHighlightNodes(nodesToHighlight);
}, [hoverContextName, manager, nodes]);
useEffect(() => {
const highlights = new Set<string>();
if (hoverContextName) {
contextWithUniqueSymbolId.forEach((ctx) => {
if (
ctx.name !== hoverContextName &&
scanContextsInAny(ctx).includes(hoverContextName)
) {
highlights.add(ctx[symbolId]);
}
});
}
setHighlightedContexts(highlights);
}, [hoverContextName, contextWithUniqueSymbolId]);
const setData = (contextValue?: ContextConf, uid?: string): void => {
const isValue = !contextValue?.resolve;
settingItemForm.resetFields();
if (isValue) {
const formValue = {
name: contextValue?.name,
type: ContextType.VALUE,
...safeDumpFields({
value: contextValue?.value,
if: contextValue?.if,
onChange: contextValue?.onChange,
}),
};
settingItemForm.setFieldsValue(formValue);
} else {
const formValue = {
name: contextValue?.name,
...((contextValue.resolve as SelectorProviderResolveConf).provider
? {
type: ContextType.SELECTOR_RESOLVE,
provider: (contextValue.resolve as SelectorProviderResolveConf)
.provider,
}
: (
contextValue?.resolve as UseProviderResolveConf
).useProvider?.includes("@")
? {
type: ContextType.FLOW_API,
flowApi: (contextValue.resolve as UseProviderResolveConf)
.useProvider,
}
: {
type: ContextType.RESOLVE,
useProvider: (contextValue.resolve as UseProviderResolveConf)
.useProvider,
}),
...safeDumpFields({
args: (contextValue.resolve as EntityResolveConf).args,
value: contextValue.value,
if: contextValue.if,
resolveIf: contextValue.resolve.if,
transform: contextValue.resolve.transform,
onReject: contextValue.resolve.onReject,
onChange: contextValue?.onChange,
}),
};
settingItemForm.setFieldsValue(formValue);
}
setSettingItem(contextValue);
setVisible(true);
settingUid.current = uid;
};
const handleOk = (): void => {
settingItemForm.submit();
};
const handleContextItemUpdate = (
contextItem: ContextConfWithSymbolId
): void => {
const targetIndex = settingUid.current
? findIndex(contextWithUniqueSymbolId, [symbolId, settingUid.current])
: contextWithUniqueSymbolId.length;
const newContext = update(contextWithUniqueSymbolId, {
[targetIndex]: {
$set: contextItem,
},
});
onContextUpdate?.(newContext);
setVisible(false);
};
const handleCancel = (): void => {
setVisible(false);
};
const handleContextItemDelete = (
e: React.MouseEvent<HTMLElement, MouseEvent>,
dataItem: ContextConfWithSymbolId
): void => {
e.stopPropagation();
// istanbul ignore next
Modal.confirm({
title: "Delete Confirm",
icon: <ExclamationCircleOutlined />,
content: (
<span>
Are you sure delete data{" "}
<strong className={styles.dangerText}>{dataItem.name}</strong>?
</span>
),
okText: "Yes",
okType: "danger",
cancelText: "No",
onOk() {
const contextToSubmit = contextWithUniqueSymbolId.filter(
(v) => v[symbolId] !== dataItem[symbolId]
);
onContextUpdate?.(contextToSubmit);
},
});
};
const handleDropItem = (dragIndex: number, hoverIndex: number): void => {
if (dragIndex === hoverIndex) {
return;
}
const dragItem = contextWithUniqueSymbolId[dragIndex];
const newContext = update(contextWithUniqueSymbolId, {
$splice: [
[dragIndex, 1],
[hoverIndex, 0, dragItem],
],
});
onContextUpdate?.(newContext);
};
const handleItemHover = (contextName?: string): void => {
setHoverContextName(contextName);
};
return (
<ToolboxPane
title={t(K.DATA)}
tooltips={
<>
<p>
<Trans t={t} i18nKey={K.DATA_VIEW_TIPS_1} />
</p>
<p>
<Trans t={t} i18nKey={K.DATA_VIEW_TIPS_2} />
</p>
<p>
<Trans t={t} i18nKey={K.DATA_VIEW_TIPS_3} />
</p>
</>
}
>
<SearchComponent placeholder={t(K.SEARCH_DATA)} onSearch={handleSearch} />
<div className={styles.wrapper}>
<Button
icon={<PlusOutlined />}
size="small"
onClick={() => setData()}
data-testid="add-data-btn"
>
{t(K.ADD_DATA)}
</Button>
<div
className={`${styles.varList} ${sharedStyles.customScrollbarContainer}`}
>
{filteredContextList?.length > 0 &&
filteredContextList.map((data, index) => (
<ContextItem
handleItemHover={handleItemHover}
data={data}
handleItemClick={() => setData(data, data[symbolId])}
handleItemDelete={(e) => handleContextItemDelete(e, data)}
handleDropItem={handleDropItem}
index={index}
canDrag={!q}
key={data[symbolId]}
highlighted={highlightedContexts.has(data[symbolId])}
/>
))}
</div>
</div>
<ContextItemFormModal
data={settingItem}
onContextItemUpdate={handleContextItemUpdate}
settingItemForm={settingItemForm}
visible={visible}
onOk={handleOk}
onCancel={handleCancel}
/>
</ToolboxPane>
);
}
Example #28
Source File: AddChild.tsx From tobira with Apache License 2.0 | 4 votes |
AddChild: React.FC<Props> = ({ parent }) => {
const { t } = useTranslation();
type FormData = {
name: string;
pathSegment: string;
};
const { register, handleSubmit, formState: { errors } } = useForm<FormData>();
const [commitError, setCommitError] = useState<JSX.Element | null>(null);
const router = useRouter();
const [commit, isInFlight] = useMutation(addChildMutation);
const onSubmit = handleSubmit(data => {
commit({
variables: {
realm: {
parent: parent.id,
name: data.name,
pathSegment: data.pathSegment,
},
},
onCompleted: response => {
const typedResponse = response as AddChildMutation$data;
const path = pathToQuery(typedResponse.addRealm.path);
router.goto(`/~manage/realm/content?path=${path}`);
},
onError: error => {
setCommitError(displayCommitError(error, t("manage.add-child.failed-to-add")));
},
});
});
const validations = realmValidations(t);
const breadcrumbs = (parent.isRoot ? parent.ancestors : parent.ancestors.concat(parent))
.map(({ name, path }) => ({ label: name, link: path }));
return (
<RealmSettingsContainer>
<Breadcrumbs path={breadcrumbs} tail={<i>{t("realm.add-sub-page")}</i>} />
<PageTitle title={t("manage.add-child.heading")} />
<p>
{
parent.isRoot
? t("manage.add-child.below-root")
: <Trans i18nKey="manage.add-child.below-this-parent">
{{ parent: parent.name }}
</Trans>
}
</p>
<Form
onSubmit={onSubmit}
css={{
margin: "32px 0",
"& > div": { marginBottom: 32 },
}}
>
<InputWithInfo info={t("manage.add-child.page-name-info")}>
<label htmlFor="name-field">{t("manage.realm.general.rename-label")}</label>
<Input
id="name-field"
css={{ width: 350, maxWidth: "100%" }}
placeholder={t("manage.realm.general.rename-label")}
error={!!errors.name}
autoFocus
{...register("name", validations.name)}
/>
{boxError(errors.name?.message)}
</InputWithInfo>
<InputWithInfo
info={<Trans i18nKey="manage.add-child.path-segment-info">
{{ illegalChars: ILLEGAL_CHARS, reservedChars: RESERVED_CHARS }}
</Trans>}
>
<label htmlFor="path-field">{t("manage.add-child.path-segment")}</label>
<PathSegmentInput
id="path-field"
base={parent.path}
error={!!errors.pathSegment}
{...register("pathSegment", validations.path)}
/>
{boxError(errors.pathSegment?.message)}
</InputWithInfo>
<div>
<div css={{ display: "flex", alignItems: "center", gap: 16 }}>
<Button type="submit" kind="happy" disabled={isInFlight}>
{t("manage.add-child.button-create-page")}
</Button>
{isInFlight && <Spinner size={20} />}
</div>
{boxError(commitError)}
</div>
</Form>
</RealmSettingsContainer>
);
}
Example #29
Source File: SubstatInput.tsx From genshin-optimizer with MIT License | 4 votes |
export default function SubstatInput({ index, artifact, setSubstat }: { index: number, artifact: ICachedArtifact | undefined, setSubstat: (index: number, substat: ISubstat) => void, }) {
const { t } = useTranslation("artifact")
const { mainStatKey = "", rarity = 5 } = artifact ?? {}
const { key = "", value = 0, rolls = [], efficiency = 0 } = artifact?.substats[index] ?? {}
const accurateValue = rolls.reduce((a, b) => a + b, 0)
const unit = KeyMap.unit(key), rollNum = rolls.length
let error: string = "", rollData: readonly number[] = [], allowedRolls = 0
if (artifact) {
// Account for the rolls it will need to fill all 4 substates, +1 for its base roll
const rarity = artifact.rarity
const { numUpgrades, high } = Artifact.rollInfo(rarity)
const maxRollNum = numUpgrades + high - 3;
allowedRolls = maxRollNum - rollNum
rollData = key ? Artifact.getSubstatRollData(key, rarity) : []
}
const rollOffset = 7 - rollData.length
if (!rollNum && key && value) error = error || t`editor.substat.error.noCalc`
if (allowedRolls < 0) error = error || t("editor.substat.error.noOverRoll", { value: allowedRolls + rollNum })
return <CardLight>
<Box sx={{ display: "flex" }}>
<ButtonGroup size="small" sx={{ width: "100%", display: "flex" }}>
<DropdownButton
startIcon={key ? StatIcon[key] : undefined}
title={key ? KeyMap.getArtStr(key) : t('editor.substat.substatFormat', { value: index + 1 })}
disabled={!artifact}
color={key ? "success" : "primary"}
sx={{ whiteSpace: "nowrap" }}>
{key && <MenuItem onClick={() => setSubstat(index, { key: "", value: 0 })}>{t`editor.substat.noSubstat`}</MenuItem>}
{allSubstatKeys.filter(key => mainStatKey !== key)
.map(k => <MenuItem key={k} selected={key === k} disabled={key === k} onClick={() => setSubstat(index, { key: k, value: 0 })} >
<ListItemIcon>{StatIcon[k]}</ListItemIcon>
<ListItemText>{KeyMap.getArtStr(k)}</ListItemText>
</MenuItem>)}
</DropdownButton>
<CustomNumberInputButtonGroupWrapper sx={{ flexBasis: 30, flexGrow: 1 }} >
<CustomNumberInput
float={unit === "%"}
placeholder={t`editor.substat.selectSub`}
value={key ? value : undefined}
onChange={value => setSubstat(index, { key, value: value ?? 0 })}
disabled={!key}
error={!!error}
sx={{
px: 1,
}}
inputProps={{
sx: { textAlign: "right" }
}}
/>
</CustomNumberInputButtonGroupWrapper>
{!!rollData.length && <TextButton>{t`editor.substat.nextRolls`}</TextButton>}
{rollData.map((v, i) => {
let newValue = cacheValueString(accurateValue + v, unit)
newValue = artifactSubstatRollCorrection[rarity]?.[key]?.[newValue] ?? newValue
return <Button key={i} color={`roll${clamp(rollOffset + i, 1, 6)}` as any} disabled={(value && !rollNum) || allowedRolls <= 0} onClick={() => setSubstat(index, { key, value: parseFloat(newValue) })}>{newValue}</Button>
})}
</ButtonGroup>
</Box>
<Box sx={{ p: 1, }}>
{error ? <SqBadge color="error">{t`ui:error`}</SqBadge> : <Grid container>
<Grid item>
<SqBadge color={rollNum === 0 ? "secondary" : `roll${clamp(rollNum, 1, 6)}`}>
{rollNum ? t("editor.substat.RollCount", { count: rollNum }) : t`editor.substat.noRoll`}
</SqBadge>
</Grid>
<Grid item flexGrow={1}>
{!!rolls.length && [...rolls].sort().map((val, i) =>
<Typography component="span" key={`${i}.${val}`} color={`roll${clamp(rollOffset + rollData.indexOf(val), 1, 6)}.main`} sx={{ ml: 1 }} >{cacheValueString(val, unit)}</Typography>)}
</Grid>
<Grid item xs="auto" flexShrink={1}>
<Typography>
<Trans t={t} i18nKey="editor.substat.eff" color="text.secondary">
Efficiency: <PercentBadge valid={true} max={rollNum * 100} value={efficiency ? efficiency : t`editor.substat.noStat` as string} />
</Trans>
</Typography>
</Grid>
</Grid>}
</Box>
</CardLight >
}