@material-ui/lab#AlertTitle TypeScript Examples
The following examples show how to use
@material-ui/lab#AlertTitle.
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: GeneralErrorAlert.tsx From abacus with GNU General Public License v2.0 | 6 votes |
export default function GeneralErrorAlert({ error }: { error?: Error }): JSX.Element | null {
const classes = useStyles()
if (error instanceof HttpResponseError) {
return (
<Alert severity='error' className={classes.root}>
<AlertTitle>
Error Response: {error.status} {error.response.statusText}
</AlertTitle>
{error.json && typeof error.json === 'object' && (error?.json as Record<string | number, unknown>).message}
</Alert>
)
} else if (error instanceof Error) {
return (
<Alert severity='error' className={classes.root}>
<AlertTitle>{error.name}:</AlertTitle>
{error.message}
</Alert>
)
}
return null
}
Example #2
Source File: App.tsx From clarity with Apache License 2.0 | 6 votes |
Alerts = observer((props: AppProps) => {
if (props.errors.lastError == null) return null;
// Not using the `data-dismiss="alert"` to dismiss via Bootstrap JS
// becuase then it doesn't re-render when there's a new error.
return (
<div id="alert-message">
<Alert severity="error" onClose={() => props.errors.dismissLast()}>
<AlertTitle>Error!</AlertTitle>
{props.errors.lastError}
</Alert>
</div>
);
})
Example #3
Source File: PromoteRc.tsx From backstage with Apache License 2.0 | 6 votes |
PromoteRc = ({ latestRelease, onSuccess }: PromoteRcProps) => {
function Body() {
if (latestRelease === null) {
return <NoLatestRelease />;
}
if (!latestRelease.prerelease) {
return (
<Box marginBottom={2}>
<Alert
data-testid={TEST_IDS.promoteRc.notRcWarning}
severity="warning"
>
<AlertTitle>
Latest Git release is not a Release Candidate
</AlertTitle>
One can only promote Release Candidates to Release Versions
</Alert>
</Box>
);
}
return <PromoteRcBody rcRelease={latestRelease} onSuccess={onSuccess} />;
}
return (
<InfoCardPlus>
<Box marginBottom={2}>
<Typography variant="h4">Promote Release Candidate</Typography>
</Box>
<Body />
</InfoCardPlus>
);
}
Example #4
Source File: snack.tsx From bitpay-browser-extension with MIT License | 6 votes |
Snack: React.FC<{ message: string; onClose: () => void }> = ({ message, onClose }) => (
<div className="snack">
<Snackbar style={position} open={!!message} autoHideDuration={6000} anchorOrigin={anchorOrigin} onClose={onClose}>
<Alert
style={menu}
severity="error"
action={
<IconButton aria-label="close" color="inherit" size="small" style={icon} onClick={onClose}>
<img src="/assets/icons/close.svg" alt="close" />
</IconButton>
}
>
<AlertTitle style={title}>Please Try Again!</AlertTitle>
{message}
</Alert>
</Snackbar>
</div>
)
Example #5
Source File: App.tsx From signer with Apache License 2.0 | 6 votes |
Alerts = observer((props: AppProps) => {
if (props.errors.lastError == null) return null;
// Not using the `data-dismiss="alert"` to dismiss via Bootstrap JS
// becuase then it doesn't re-render when there's a new error.
return (
<div id="alert-message">
<Alert severity="error" onClose={() => props.errors.dismissLast()}>
<AlertTitle>Error!</AlertTitle>
{props.errors.lastError}
</Alert>
</div>
);
})
Example #6
Source File: AlertUploadSize.tsx From bee-dashboard with BSD 3-Clause "New" or "Revised" License | 6 votes |
export default function UploadSizeAlert(props: Props): ReactElement | null {
const classes = useStyles()
const totalSize = props.files.reduce((previous, current) => previous + current.size, 0)
const aboveLimit = totalSize >= LIMIT
return (
<Collapse in={aboveLimit}>
<div className={classes.root}>
<Alert severity="warning">
<AlertTitle>Warning</AlertTitle>
The files you are trying to upload are above the recommended size. The chunks may not be synchronised properly
over the network.
</Alert>
</div>
</Collapse>
)
}
Example #7
Source File: Patch.tsx From backstage with Apache License 2.0 | 5 votes |
function BodyWrapper({
latestRelease,
releaseBranch,
onSuccess,
ctaMessage,
}: PatchProps & { ctaMessage: string }) {
const { project } = useProjectContext();
if (latestRelease === null) {
return <NoLatestRelease />;
}
if (releaseBranch === null) {
return <NoLatestRelease />;
}
const bumpedTag = getBumpedTag({
project,
tag: latestRelease.tagName,
bumpLevel: 'patch',
});
if (bumpedTag.error !== undefined) {
return (
<Alert severity="error">
{bumpedTag.error.title && (
<AlertTitle>{bumpedTag.error.title}</AlertTitle>
)}
{bumpedTag.error.subtitle}
</Alert>
);
}
return (
<PatchBody
bumpedTag={bumpedTag.bumpedTag}
latestRelease={latestRelease}
releaseBranch={releaseBranch}
onSuccess={onSuccess}
tagParts={bumpedTag.tagParts}
ctaMessage={ctaMessage}
/>
);
}
Example #8
Source File: Footer.tsx From knboard with MIT License | 5 votes |
Footer = () => {
const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(
null
);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const open = Boolean(anchorEl);
const id = open ? "about-popover" : undefined;
return (
<Container>
<List>
<Item>
<Button
aria-describedby={id}
onClick={handleClick}
css={css`
padding: 0;
text-transform: initial;
color: #888;
font-weight: 400;
&:hover {
background-color: initial;
}
`}
>
About
</Button>
</Item>
</List>
<Popover
id={id}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: "top",
horizontal: "center",
}}
transformOrigin={{
vertical: "bottom",
horizontal: "center",
}}
>
<Alert
severity="info"
css={css`
padding: 1rem 1rem 2rem 1rem;
max-width: 400px;
`}
>
<AlertTitle>About</AlertTitle>
<p>
<b>Knboard</b> is an app that helps visualize your work using kanban
boards, maximizing efficiency.
</p>
It is an <b>open-source</b> project built using Django & React,
available on{" "}
<Link
href="https://github.com/rrebase/knboard"
target="_blank"
rel="noopener"
>
GitHub
</Link>
.
</Alert>
</Popover>
</Container>
);
}
Example #9
Source File: CreateReleaseCandidate.tsx From backstage with Apache License 2.0 | 4 votes |
CreateReleaseCandidate = ({
defaultBranch,
latestRelease,
releaseBranch,
onSuccess,
}: CreateReleaseCandidateProps) => {
const { project } = useProjectContext();
const [semverBumpLevel, setSemverBumpLevel] = useState<'major' | 'minor'>(
SEMVER_PARTS.minor,
);
const [releaseCandidateGitInfo, setReleaseCandidateGitInfo] = useState(
getReleaseCandidateGitInfo({ latestRelease, project, semverBumpLevel }),
);
useEffect(() => {
setReleaseCandidateGitInfo(
getReleaseCandidateGitInfo({ latestRelease, project, semverBumpLevel }),
);
}, [semverBumpLevel, setReleaseCandidateGitInfo, latestRelease, project]);
const { progress, responseSteps, run, runInvoked } =
useCreateReleaseCandidate({
defaultBranch,
latestRelease,
releaseCandidateGitInfo,
project,
onSuccess,
});
if (responseSteps.length > 0) {
return (
<ResponseStepDialog
progress={progress}
responseSteps={responseSteps}
title="Create Release Candidate"
/>
);
}
if (releaseCandidateGitInfo.error !== undefined) {
return (
<InfoCardPlusWrapper>
<Alert severity="error">
{releaseCandidateGitInfo.error.title && (
<AlertTitle>{releaseCandidateGitInfo.error.title}</AlertTitle>
)}
{releaseCandidateGitInfo.error.subtitle}
</Alert>
</InfoCardPlusWrapper>
);
}
const tagAlreadyExists =
latestRelease !== null &&
latestRelease.tagName === releaseCandidateGitInfo.rcReleaseTag;
const conflictingPreRelease =
latestRelease !== null && latestRelease.prerelease;
return (
<InfoCardPlusWrapper>
{project.versioningStrategy === 'semver' &&
latestRelease &&
!conflictingPreRelease && (
<Box marginBottom={2} data-testid={TEST_IDS.createRc.semverSelect}>
<FormControl style={{ margin: 5, minWidth: 250 }}>
<InputLabel>Select bump severity</InputLabel>
<Select
value={semverBumpLevel}
onChange={({ target: { value: semverSeverity } }: any) => {
setSemverBumpLevel(semverSeverity);
}}
>
<MenuItem value={SEMVER_PARTS.minor}>
{SEMVER_PARTS.minor}
</MenuItem>
<MenuItem value={SEMVER_PARTS.major}>
{SEMVER_PARTS.major}
</MenuItem>
</Select>
</FormControl>
</Box>
)}
{conflictingPreRelease || tagAlreadyExists ? (
<>
{conflictingPreRelease && (
<Box marginBottom={2}>
<Alert severity="warning">
The most recent release is already a Release Candidate
</Alert>
</Box>
)}
{tagAlreadyExists && (
<Box marginBottom={2}>
<Alert severity="warning">
There's already a tag named{' '}
<strong>{releaseCandidateGitInfo.rcReleaseTag}</strong>
</Alert>
</Box>
)}
</>
) : (
<Box marginBottom={2}>
<Typography>
<Differ
icon="branch"
current={releaseBranch?.name}
next={releaseCandidateGitInfo.rcBranch}
/>
</Typography>
<Typography>
<Differ
icon="tag"
current={latestRelease?.tagName}
next={releaseCandidateGitInfo.rcReleaseTag}
/>
</Typography>
</Box>
)}
<Button
data-testid={TEST_IDS.createRc.cta}
disabled={conflictingPreRelease || tagAlreadyExists || runInvoked}
variant="contained"
color="primary"
onClick={() => run()}
>
Create Release Candidate
</Button>
</InfoCardPlusWrapper>
);
}
Example #10
Source File: Features.tsx From backstage with Apache License 2.0 | 4 votes |
export function Features({
features,
}: {
features: ComponentProps<typeof GitReleaseManager>['features'];
}) {
const pluginApiClient = useApi(gitReleaseManagerApiRef);
const { project } = useProjectContext();
const { gitBatchInfo, fetchGitBatchInfo } = useGetGitBatchInfo({
pluginApiClient,
project,
});
const { versioningStrategyMatches } = useVersioningStrategyMatchesRepoTags({
latestReleaseTagName: gitBatchInfo.value?.latestRelease?.tagName,
project,
repositoryName: gitBatchInfo.value?.repository.name,
});
if (gitBatchInfo.error) {
return (
<Alert severity="error">
Error occurred while fetching information for "{project.owner}/
{project.repo}" ({gitBatchInfo.error.message})
</Alert>
);
}
if (gitBatchInfo.loading) {
return <Progress />;
}
if (gitBatchInfo.value === undefined) {
return <Alert severity="error">Failed to fetch latest Git release</Alert>;
}
if (!gitBatchInfo.value.repository.pushPermissions) {
return (
<Alert severity="error">
You lack push permissions for repository "{project.owner}/{project.repo}
"
</Alert>
);
}
const { tagNameError } = validateTagName({
project,
tagName: gitBatchInfo.value.latestRelease?.tagName,
});
if (tagNameError) {
return (
<Alert severity="error">
{tagNameError.title && <AlertTitle>{tagNameError.title}</AlertTitle>}
{tagNameError.subtitle}
</Alert>
);
}
let CustomFeatures =
features?.custom?.factory({
latestRelease: gitBatchInfo.value.latestRelease,
project,
releaseBranch: gitBatchInfo.value.releaseBranch,
repository: gitBatchInfo.value.repository,
}) ?? null;
if (Array.isArray(CustomFeatures)) {
CustomFeatures = CustomFeatures.map((CustomFeature, index) => (
<React.Fragment key={`grm--custom-feature--${index}`}>
{CustomFeature}
</React.Fragment>
));
}
return (
<RefetchContext.Provider value={{ fetchGitBatchInfo }}>
<ErrorBoundary>
{gitBatchInfo.value.latestRelease && !versioningStrategyMatches && (
<Alert severity="warning" style={{ marginBottom: 20 }}>
Versioning mismatch, expected {project.versioningStrategy} version,
got "{gitBatchInfo.value.latestRelease.tagName}"
</Alert>
)}
{!gitBatchInfo.value.latestRelease && (
<Alert severity="info" style={{ marginBottom: 20 }}>
This repository doesn't have any releases yet
</Alert>
)}
{!gitBatchInfo.value.releaseBranch && (
<Alert severity="info" style={{ marginBottom: 20 }}>
This repository doesn't have any release branches
</Alert>
)}
{!features?.info?.omit && (
<Info
latestRelease={gitBatchInfo.value.latestRelease}
releaseBranch={gitBatchInfo.value.releaseBranch}
statsEnabled={features?.stats?.omit !== true}
/>
)}
{!features?.createRc?.omit && (
<CreateReleaseCandidate
latestRelease={gitBatchInfo.value.latestRelease}
releaseBranch={gitBatchInfo.value.releaseBranch}
defaultBranch={gitBatchInfo.value.repository.defaultBranch}
onSuccess={features?.createRc?.onSuccess}
/>
)}
{!features?.promoteRc?.omit && (
<PromoteRc
latestRelease={gitBatchInfo.value.latestRelease}
onSuccess={features?.promoteRc?.onSuccess}
/>
)}
{!features?.patch?.omit && (
<Patch
latestRelease={gitBatchInfo.value.latestRelease}
releaseBranch={gitBatchInfo.value.releaseBranch}
onSuccess={features?.patch?.onSuccess}
/>
)}
{CustomFeatures}
</ErrorBoundary>
</RefetchContext.Provider>
);
}
Example #11
Source File: PatchBody.tsx From backstage with Apache License 2.0 | 4 votes |
PatchBody = ({
bumpedTag,
latestRelease,
releaseBranch,
onSuccess,
tagParts,
ctaMessage,
}: PatchBodyProps) => {
const pluginApiClient = useApi(gitReleaseManagerApiRef);
const { project } = useProjectContext();
const [checkedCommitIndex, setCheckedCommitIndex] = useState(-1);
const gitDataResponse = useAsync(async () => {
const [
{ recentCommits: recentCommitsOnDefaultBranch },
{ recentCommits: recentCommitsOnReleaseBranch },
] = await Promise.all([
pluginApiClient.getRecentCommits({
owner: project.owner,
repo: project.repo,
}),
pluginApiClient.getRecentCommits({
owner: project.owner,
repo: project.repo,
releaseBranchName: releaseBranch.name,
}),
]);
return {
recentCommitsOnDefaultBranch,
recentCommitsOnReleaseBranch,
};
});
const { progress, responseSteps, run, runInvoked } = usePatch({
bumpedTag,
latestRelease,
project,
tagParts,
onSuccess,
});
if (responseSteps.length > 0) {
return (
<ResponseStepDialog
progress={progress}
responseSteps={responseSteps}
title={ctaMessage}
/>
);
}
if (gitDataResponse.error) {
return (
<Alert data-testid={TEST_IDS.patch.error} severity="error">
Unexpected error: {gitDataResponse.error.message}
</Alert>
);
}
if (gitDataResponse.loading) {
return (
<Box data-testid={TEST_IDS.patch.loading}>
<Progress />
</Box>
);
}
function Description() {
return (
<>
{!latestRelease.prerelease && (
<Box marginBottom={2}>
<Alert data-testid={TEST_IDS.patch.notPrerelease} severity="info">
<AlertTitle>
The current Git release is a <b>Release Version</b>
</AlertTitle>
It's still possible to patch it, but be extra mindful of changes
</Alert>
</Box>
)}
<Box marginBottom={2}>
<Typography>
Patches the release branch, creates a new tag and updates the Git
release. A dry run on a temporary branch will run prior to patching
the release branch to ensure there's no merge conflicts. Manual
patching is recommended should the dry run fail.
</Typography>
</Box>
<Box marginBottom={2}>
<Typography>
<Differ
icon="tag"
current={latestRelease.tagName}
next={bumpedTag}
/>
</Typography>
</Box>
</>
);
}
function CommitList() {
if (!gitDataResponse.value?.recentCommitsOnDefaultBranch) {
return null;
}
return (
<List>
{gitDataResponse.value.recentCommitsOnDefaultBranch.map(
(commit, index) => {
// FIXME: Performance improvement opportunity: Convert to object lookup
const commitExistsOnReleaseBranch =
!!gitDataResponse.value?.recentCommitsOnReleaseBranch.find(
releaseBranchCommit =>
releaseBranchCommit.sha === commit.sha ||
// The selected patch commit's sha is included in the commit message,
// which means it's part of a previous patch
releaseBranchCommit.commit.message.includes(
getPatchCommitSuffix({ commitSha: commit.sha }),
),
);
const hasNoParent = !commit.firstParentSha;
return (
<div style={{ position: 'relative' }} key={`commit-${index}`}>
{commitExistsOnReleaseBranch && (
<Paper
elevation={3}
style={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate3d(-50%,-50%,0)',
zIndex: 10,
color: 'green',
padding: 6,
background: 'rgba(244,244,244,1)',
borderRadius: 8,
}}
>
<FileCopyIcon
fontSize="small"
style={{ verticalAlign: 'middle' }}
/>{' '}
Already exists on <b>{releaseBranch?.name}</b>
</Paper>
)}
<ListItem
disabled={
runInvoked || commitExistsOnReleaseBranch || hasNoParent
}
role={undefined}
dense
button
onClick={() => {
if (index === checkedCommitIndex) {
setCheckedCommitIndex(-1);
} else {
setCheckedCommitIndex(index);
}
}}
>
<ListItemIcon>
<Checkbox
edge="start"
checked={checkedCommitIndex === index}
tabIndex={-1}
/>
</ListItemIcon>
<ListItemText
style={{ marginRight: 15 }}
id={commit.sha}
primary={commit.commit.message}
secondary={
<>
<Link
color="primary"
to={commit.htmlUrl}
target="_blank"
>
{commit.sha}
</Link>{' '}
{commit.author.htmlUrl && (
<Link
color="primary"
to={commit.author.htmlUrl}
target="_blank"
>
@{commit.author.login}
</Link>
)}
</>
}
/>
<ListItemSecondaryAction>
<IconButton
aria-label="commit"
disabled={
runInvoked ||
commitExistsOnReleaseBranch ||
!releaseBranch
}
onClick={() => {
const repoPath = pluginApiClient.getRepoPath({
owner: project.owner,
repo: project.repo,
});
const host = pluginApiClient.getHost();
const newTab = window.open(
`https://${host}/${repoPath}/compare/${releaseBranch?.name}...${commit.sha}`,
'_blank',
);
newTab?.focus();
}}
>
<OpenInNewIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
</div>
);
},
)}
</List>
);
}
return (
<Box data-testid={TEST_IDS.patch.body}>
<Description />
<Box style={{ maxHeight: 450, overflowY: 'auto' }}>
<CommitList />
</Box>
<Button
disabled={checkedCommitIndex === -1 || progress > 0}
variant="contained"
color="primary"
onClick={() => {
const selectedPatchCommit =
gitDataResponse.value?.recentCommitsOnDefaultBranch[
checkedCommitIndex
];
if (!selectedPatchCommit) {
throw new GitReleaseManagerError(
'Could not find selected patch commit',
);
}
run(selectedPatchCommit);
}}
>
{ctaMessage}
</Button>
</Box>
);
}
Example #12
Source File: OverviewTrends.tsx From backstage with Apache License 2.0 | 4 votes |
OverviewTrends = () => {
const [days, setDays] = useState(14);
const theme = useTheme<BackstageTheme>();
const classes = useStyles();
const client = useApi(xcmetricsApiRef);
const buildCountsResult = useAsync(
async () => client.getBuildCounts(days),
[days],
);
const buildTimesResult = useAsync(
async () => client.getBuildTimes(days),
[days],
);
if (buildCountsResult.loading && buildTimesResult.loading) {
return <Progress />;
}
const sumBuilds = sumField(b => b.builds, buildCountsResult.value);
const sumErrors = sumField(b => b.errors, buildCountsResult.value);
const errorRate = sumBuilds && sumErrors ? sumErrors / sumBuilds : undefined;
const averageBuildDurationP50 = getAverageDuration(
buildTimesResult.value,
b => b.durationP50,
);
const averageBuildDurationP95 = getAverageDuration(
buildTimesResult.value,
b => b.durationP95,
);
const totalBuildTime = sumField(t => t.totalDuration, buildTimesResult.value);
return (
<>
<Select
selected={days}
items={DAYS_SELECT_ITEMS}
label="Trends for"
onChange={selection => setDays(selection as number)}
/>
{buildCountsResult.error && (
<Alert severity="error" className={classes.spacingVertical}>
<AlertTitle>Failed to fetch build counts</AlertTitle>
{buildCountsResult?.error?.message}
</Alert>
)}
{buildTimesResult.error && (
<Alert severity="error" className={classes.spacingVertical}>
<AlertTitle>Failed to fetch build times</AlertTitle>
{buildTimesResult?.error?.message}
</Alert>
)}
{(!buildCountsResult.error || !buildTimesResult.error) && (
<div className={classes.spacingVertical}>
<Trend
title="Build Time"
color={theme.palette.secondary.main}
data={getValues(e => e.durationP50, buildTimesResult.value)}
/>
<Trend
title="Error Rate"
color={theme.palette.status.warning}
data={getErrorRatios(buildCountsResult.value)}
/>
<Trend
title="Build Count"
color={theme.palette.primary.main}
data={getValues(e => e.builds, buildCountsResult.value)}
/>
<Grid
container
spacing={3}
direction="row"
className={classes.spacingTop}
>
<DataValueGridItem field="Build Count" value={sumBuilds} />
<DataValueGridItem field="Error Count" value={sumErrors} />
<DataValueGridItem
field="Error Rate"
value={errorRate && formatPercentage(errorRate)}
/>
<DataValueGridItem
field="Avg. Build Time (P50)"
value={averageBuildDurationP50}
/>
<DataValueGridItem
field="Avg. Build Time (P95)"
value={averageBuildDurationP95}
/>
<DataValueGridItem
field="Total Build Time"
value={totalBuildTime && formatDuration(totalBuildTime)}
/>
</Grid>
</div>
)}
</>
);
}
Example #13
Source File: AccountEnterPage.tsx From clearflask with Apache License 2.0 | 4 votes |
renderCoupon(isLoggedIn: boolean) {
const couponId = this.state.couponId !== undefined ? this.state.couponId : this.props.couponId || '';
return (
<EnterTemplate
title={this.props.t('redeem-coupon')}
renderContent={submitButton => (
<>
<TextField
variant='outlined'
fullWidth
margin='normal'
label={this.props.t('coupon-code')}
placeholder='XXXXXXXX'
value={couponId}
onChange={e => this.setState({ couponId: e.target.value })}
disabled={this.state.isSubmitting || !!this.state.couponPlan || !!this.state.couponRedeemedByYou}
/>
<Collapse in={!!this.state.couponRedeemedByYou}>
<Alert className={this.props.classes.alert} severity='success'>
<AlertTitle>Success!</AlertTitle>
This coupon has already been applied to your account.
</Alert>
</Collapse>
<Collapse in={!!this.state.couponPlan && !this.state.couponRedeemedByYou}>
{!!this.state.couponPlan && (
<PricingPlan plan={this.state.couponPlan} />
)}
</Collapse>
<Collapse in={!this.state.couponRedeemedByYou && !!this.state.couponPlan}>
<Alert className={this.props.classes.alert} severity='info'>
{!isLoggedIn ? 'This plan will be applied upon sign-up or login' : 'This plan will replace your current plan on your account.'}
</Alert>
</Collapse>
{submitButton}
<Collapse in={!!this.state.couponError}>
<Alert className={this.props.classes.alert} severity='warning'>
{this.state.couponError}
</Alert>
</Collapse>
</>
)}
submitTitle={!!this.state.couponRedeemedByYou
? this.props.t('continue')
: (!this.state.couponPlan
? this.props.t('check')
: (!isLoggedIn
? this.props.t('continue')
: this.props.t('redeem')))}
submitDisabled={!couponId}
isSubmitting={this.state.isSubmitting}
onSubmit={async () => {
if (!couponId) return;
if (!!this.state.couponRedeemedByYou) {
// Already redeemed by you
this.props.history.push('/dashboard');
} else if (!this.state.couponPlan) {
// Need to check couponn
await this.onCouponCheck(couponId);
} else if (!isLoggedIn) {
// Redirect to signup for a valid code
this.props.history.push('/signup/', {
[ADMIN_ENTER_COUPON_ID]: couponId,
[ADMIN_LOGIN_REDIRECT_TO]: `/coupon/${couponId}`,
})
} else {
// Accept code on own account
this.setState({ isSubmitting: true });
try {
await (await ServerAdmin.get().dispatchAdmin()).accountAcceptCouponAdmin({
couponId,
});
this.setState({
couponRedeemedByYou: true,
couponError: undefined,
});
} finally {
this.setState({ isSubmitting: false });
}
}
}}
footer={(!this.state.couponRedeemedByYou && !!this.state.couponPlan && !isLoggedIn) ? {
text: this.props.t('have-an-account'),
actionText: this.props.t('log-in-here'),
linkTo: {
pathname: '/login',
state: {
[ADMIN_ENTER_COUPON_ID]: couponId,
[ADMIN_LOGIN_REDIRECT_TO]: `/coupon/${couponId}`,
},
},
} : undefined}
layout={this.props.type}
/>
);
}
Example #14
Source File: Profile.tsx From knboard with MIT License | 4 votes |
Profile = () => {
const theme = useTheme();
const dispatch = useDispatch();
const userDetail = useSelector(
(state: RootState) => state.profile.userDetail
);
const apiErrors = useSelector((state: RootState) => state.profile.apiErrors);
const loading = useSelector((state: RootState) => state.profile.loading);
const { register, errors, handleSubmit, setError } = useForm<FormData>({
mode: "onChange",
});
React.useEffect(() => {
dispatch(fetchUserDetail());
dispatch(fetchAvatarList());
}, [userDetail?.id]);
React.useEffect(() => {
if (apiErrors) {
for (const errorKey in apiErrors) {
// @ts-ignore
setError(errorKey, "api_error", apiErrors[errorKey]);
}
}
}, [apiErrors]);
if (!userDetail) {
return null;
}
const onSubmit = async (data: FormData) => {
dispatch(updateUser({ ...userDetail, ...data }));
};
return (
<Container maxWidth="sm">
<SEO title="Profile" />
{userDetail.is_guest && (
<Alert
severity="warning"
variant="outlined"
css={css`
margin: 1rem 0;
`}
>
<AlertTitle>Warning</AlertTitle>
Guest accounts are deleted 24 hours after creation!
</Alert>
)}
<Title>About</Title>
<Divider />
<FormContainer theme={theme}>
<UserAvatar />
<UserForm onSubmit={handleSubmit(onSubmit)}>
<Fields>
<Row>
<TextField
id="username"
name="username"
inputRef={register({ required: "This field is required" })}
defaultValue={userDetail.username}
helperText={errors.username?.message}
error={Boolean(errors.username)}
label="Username"
variant="outlined"
margin="dense"
fullWidth
/>
</Row>
<Row>
<TextField
id="first_name"
name="first_name"
inputRef={register()}
defaultValue={userDetail.first_name}
helperText={errors.first_name?.message}
error={Boolean(errors.first_name)}
label="First name"
variant="outlined"
margin="dense"
fullWidth
/>
</Row>
<Row>
<TextField
id="last_name"
name="last_name"
inputRef={register()}
defaultValue={userDetail.last_name}
helperText={errors.last_name?.message}
error={Boolean(errors.last_name)}
label="Last name"
variant="outlined"
margin="dense"
fullWidth
/>
</Row>
<Row>
<TextField
id="email"
name="email"
inputRef={register({
pattern: {
value: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
message: "Invalid email",
},
})}
defaultValue={userDetail.email}
helperText={errors.email?.message}
error={Boolean(errors.email)}
label="Email"
variant="outlined"
margin="dense"
fullWidth
/>
</Row>
<Button
variant="contained"
color="primary"
type="submit"
disabled={loading}
data-testid="profile-save"
css={css`
margin: 1rem 0;
text-align: right;
`}
>
Save
</Button>
</Fields>
</UserForm>
</FormContainer>
</Container>
);
}