react-icons/io#IoMdLogOut TypeScript Examples
The following examples show how to use
react-icons/io#IoMdLogOut.
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: Modal.tsx From hub with Apache License 2.0 | 4 votes |
OptOutModal = (props: Props) => {
const { ctx } = useContext(AppCtx);
const [apiError, setApiError] = useState<string | null>(null);
const [repoItem, setRepoItem] = useState<Repository | null>(null);
const [eventKind, setEventKind] = useState<EventKind>(EventKind.RepositoryTrackingErrors);
const [isSending, setIsSending] = useState<boolean>(false);
const [userOrganizations, setUserOrganizations] = useState<string[] | undefined>(undefined);
const onCloseModal = () => {
setRepoItem(null);
props.onClose();
};
const submitForm = () => {
if (!isNull(repoItem)) {
addOptOut();
}
};
const onRepoSelect = (repo: Repository): void => {
setRepoItem(repo);
};
async function getAllUserOrganizations() {
try {
const orgs = await API.getAllUserOrganizations();
const orgsList = orgs.map((org: Organization) => org.name);
setUserOrganizations(orgsList);
} catch (err: any) {
setUserOrganizations([]);
}
}
useEffect(() => {
getAllUserOrganizations();
}, []); /* eslint-disable-line react-hooks/exhaustive-deps */
async function addOptOut() {
try {
setIsSending(true);
await API.addOptOut(repoItem!.repositoryId!, eventKind);
setRepoItem(null);
setIsSending(false);
props.onSuccess();
props.onClose();
} catch (err: any) {
setIsSending(false);
if (err.kind !== ErrorKind.Unauthorized) {
alertDispatcher.postAlert({
type: 'danger',
message: `An error occurred adding the opt-out entry for ${props.getNotificationTitle(
eventKind
)} notifications for repository ${repoItem!.displayName || repoItem!.name}, please try again later.`,
});
}
}
}
const getPublisher = (repo: Repository) => (
<small className="ms-0 ms-sm-2">
<span className="d-none d-sm-inline">(</span>
<small className="d-none d-md-inline text-muted me-1 text-uppercase">Publisher: </small>
<div className={`d-inline me-1 ${styles.tinyIcon}`}>{repo.userAlias ? <FaUser /> : <MdBusiness />}</div>
<span>{repo.userAlias || repo.organizationDisplayName || repo.organizationName}</span>
<span className="d-none d-sm-inline">)</span>
</small>
);
return (
<Modal
header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>Add opt-out entry</div>}
open={props.open}
modalDialogClassName={styles.modal}
closeButton={
<button
className="btn btn-sm btn-outline-secondary"
type="button"
disabled={isNull(repoItem) || isSending}
onClick={submitForm}
aria-label="Add opt-out entry"
>
{isSending ? (
<>
<span className="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" />
<span className="ms-2">Opting out</span>
</>
) : (
<div className="d-flex flex-row align-items-center text-uppercase">
<IoMdLogOut className="me-2" />
<div>Opt-out</div>
</div>
)}
</button>
}
onClose={onCloseModal}
error={apiError}
cleanError={() => setApiError(null)}
noScrollable
>
<div className="w-100 position-relative">
<label className={`form-label fw-bold ${styles.label}`} htmlFor="kind">
Events
</label>
<div className="d-flex flex-column flex-wrap pb-2">
{REPOSITORY_SUBSCRIPTIONS_LIST.map((subs: SubscriptionItem) => {
return (
<div className="mb-2" key={`radio_${subs.name}`}>
<div className="form-check text-nowrap my-1 my-md-0">
<input
className="form-check-input"
type="radio"
name="kind"
id={subs.name}
value={subs.kind}
disabled={!subs.enabled}
checked={subs.kind === eventKind}
onChange={() => setEventKind(subs.kind)}
required
/>
<label className="form-check-label" htmlFor={subs.name}>
<div className="d-flex flex-row align-items-center ms-2">
{subs.icon}
<div className="ms-1">{subs.title}</div>
</div>
</label>
</div>
</div>
);
})}
</div>
<div className="d-flex flex-column mb-3">
<label className={`form-label fw-bold ${styles.label}`} htmlFor="description">
Repository
</label>
<small className="mb-2">Select repository:</small>
{!isNull(repoItem) ? (
<div
data-testid="activeRepoItem"
className={`border border-secondary w-100 rounded mt-1 ${styles.repoWrapper}`}
>
<div className="d-flex flex-row flex-nowrap align-items-stretch justify-content-between">
<div className="flex-grow-1 text-truncate py-2">
<div className="d-flex flex-row align-items-center h-100 text-truncate">
<div className="d-none d-md-inline">
<RepositoryIcon kind={repoItem.kind} className={`mx-3 ${styles.icon}`} />
</div>
<div className="ms-2 me-2 me-sm-0 fw-bold mb-0 text-truncate">
{repoItem.name}
<span className="d-inline d-sm-none">
<span className="mx-2">/</span>
{getPublisher(repoItem)}
</span>
</div>
<div className="px-2 ms-auto w-50 text-dark text-truncate d-none d-sm-inline">
{getPublisher(repoItem)}
</div>
</div>
</div>
<div>
<button
className={`btn btn-close h-100 rounded-0 border-start px-3 py-0 ${styles.closeButton}`}
onClick={() => setRepoItem(null)}
aria-label="Close"
></button>
</div>
</div>
</div>
) : (
<div className={`mt-2 ${styles.searchWrapper}`}>
<SearchRepositories
label="repo-subscriptions"
disabledRepositories={{
ids: props.disabledList,
}}
extraQueryParams={{ user: ctx.user ? [ctx.user.alias] : [], org: userOrganizations || [] }}
onSelection={onRepoSelect}
onAuthError={props.onAuthError}
visibleUrl={false}
/>
</div>
)}
</div>
</div>
</Modal>
);
}
Example #2
Source File: index.tsx From hub with Apache License 2.0 | 4 votes |
RepositoriesSection = (props: Props) => {
const title = useRef<HTMLDivElement>(null);
const [isLoading, setIsLoading] = useState(false);
const [optOutList, setOptOutList] = useState<OptOutByRepo[] | undefined>(undefined);
const [optOutFullList, setOptOutFullList] = useState<OptOutByRepo[] | undefined>(undefined);
const [repoIdsList, setRepoIdsList] = useState<string[]>([]);
const [optOutItems, setOptOutItems] = useState<OptOutItem[] | undefined>(undefined);
const [modalStatus, setModalStatus] = useState<boolean>(false);
const [activePage, setActivePage] = useState<number>(1);
const calculateOffset = (pageNumber?: number): number => {
return DEFAULT_LIMIT * ((pageNumber || activePage) - 1);
};
const [offset, setOffset] = useState<number>(calculateOffset());
const [total, setTotal] = useState<number | undefined>(undefined);
const onPageNumberChange = (pageNumber: number): void => {
setOffset(calculateOffset(pageNumber));
setActivePage(pageNumber);
if (title && title.current) {
title.current.scrollIntoView({ block: 'start', inline: 'nearest', behavior: 'smooth' });
}
};
const getNotificationTitle = (kind: EventKind): string => {
let title = '';
const notif = REPOSITORY_SUBSCRIPTIONS_LIST.find((subs: SubscriptionItem) => subs.kind === kind);
if (!isUndefined(notif)) {
title = notif.title.toLowerCase();
}
return title;
};
const getVisibleOptOut = (items: OptOutByRepo[]): OptOutByRepo[] => {
if (isUndefined(items)) return [];
return items.slice(offset, offset + DEFAULT_LIMIT);
};
const sortOptOutList = (items: OptOutItem[]): OptOutByRepo[] => {
let list: OptOutByRepo[] = [];
items.forEach((item: OptOutItem) => {
const itemIndex = list.findIndex(
(obr: OptOutByRepo) => obr.repository.repositoryId === item.repository.repositoryId
);
if (itemIndex >= 0) {
list[itemIndex] = { ...list[itemIndex], optOutItems: [...list[itemIndex].optOutItems, item] };
} else {
list.push({
repository: item.repository,
optOutItems: [item],
});
}
});
return sortBy(list, 'repository.name');
};
async function getOptOutList(callback?: () => void) {
try {
setIsLoading(true);
const items = await API.getAllOptOut();
const formattedItems = sortOptOutList(items);
setOptOutItems(items);
setOptOutFullList(formattedItems);
setRepoIdsList(formattedItems ? formattedItems.map((item: OptOutByRepo) => item.repository.repositoryId!) : []);
setTotal(formattedItems.length);
const newVisibleItems = getVisibleOptOut(formattedItems);
// When current page is empty after changes
if (newVisibleItems.length === 0 && activePage !== 1) {
onPageNumberChange(1);
} else {
setOptOutList(newVisibleItems);
}
setIsLoading(false);
} catch (err: any) {
setIsLoading(false);
if (err.kind !== ErrorKind.Unauthorized) {
alertDispatcher.postAlert({
type: 'danger',
message: 'An error occurred getting your opt-out entries list, please try again later.',
});
setOptOutFullList([]);
setOptOutList([]);
} else {
props.onAuthError();
}
} finally {
if (callback) {
callback();
}
}
}
async function changeSubscription(changeProps: ChangeSubsProps) {
const { data, callback } = { ...changeProps };
try {
if (!isUndefined(data.optOutId)) {
await API.deleteOptOut(data.optOutId);
} else {
await API.addOptOut(data.repoId, data.kind);
}
getOptOutList(callback);
} catch (err: any) {
callback();
if (err.kind !== ErrorKind.Unauthorized) {
alertDispatcher.postAlert({
type: 'danger',
message: `An error occurred ${
!isUndefined(data.optOutId) ? 'deleting' : 'adding'
} the opt-out entry for ${getNotificationTitle(data.kind)} notifications for repository ${
data.repoName
}, please try again later.`,
});
getOptOutList(); // Get opt-out if changeSubscription fails
} else {
props.onAuthError();
}
}
}
useEffect(() => {
getOptOutList();
}, []); /* eslint-disable-line react-hooks/exhaustive-deps */
useEffect(() => {
setOptOutList(getVisibleOptOut(optOutFullList || []));
}, [activePage]); /* eslint-disable-line react-hooks/exhaustive-deps */
return (
<div className="mt-5 pt-3">
{(isUndefined(optOutList) || isLoading) && <Loading />}
<div className="d-flex flex-row align-items-start justify-content-between pb-2">
<div ref={title} className={`h4 pb-0 ${styles.title}`}>
Repositories
</div>
<div>
<button
className={`btn btn-outline-secondary btn-sm text-uppercase ${styles.btnAction}`}
onClick={() => setModalStatus(true)}
aria-label="Open opt-out modal"
>
<div className="d-flex flex-row align-items-center justify-content-center">
<IoMdLogOut />
<span className="d-none d-md-inline ms-2">Opt-out</span>
</div>
</button>
</div>
</div>
<div className="mt-3 mt-md-3">
<p>
Repositories notifications are <span className="fw-bold">enabled by default</span>. However, you can opt-out
of notifications for certain kinds of events that happen in any of the repositories you can manage.
</p>
<p>
You will <span className="fw-bold">NOT</span> receive notifications when an event that matches any of the
repositories in the list is fired.
</p>
<div className="mt-4 mt-md-5">
{!isUndefined(optOutList) && optOutList.length > 0 && (
<div className="row">
<div className="col-12 col-xxxl-10">
<table className={`table table-bordered table-hover ${styles.table}`} data-testid="repositoriesList">
<thead>
<tr className={styles.tableTitle}>
<th scope="col" className={`align-middle text-center d-none d-sm-table-cell ${styles.fitCell}`}>
Kind
</th>
<th scope="col" className="align-middle w-50">
Repository
</th>
<th scope="col" className="align-middle w-50 d-none d-sm-table-cell">
Publisher
</th>
{REPOSITORY_SUBSCRIPTIONS_LIST.map((subs: SubscriptionItem) => (
<th
scope="col"
className={`align-middle text-nowrap ${styles.fitCell}`}
key={`title_${subs.kind}`}
>
<div className="d-flex flex-row align-items-center justify-content-center">
{subs.icon}
{subs.shortTitle && <span className="d-inline d-lg-none ms-2">{subs.shortTitle}</span>}
<span className="d-none d-lg-inline ms-2">{subs.title}</span>
</div>
</th>
))}
</tr>
</thead>
<tbody className={styles.body}>
{optOutList.map((item: OptOutByRepo) => {
const repoInfo: Repository = item.repository;
return (
<tr key={`subs_${repoInfo.repositoryId}`} data-testid="optOutRow">
<td className="align-middle text-center d-none d-sm-table-cell">
<RepositoryIcon kind={repoInfo.kind} className={`h-auto ${styles.icon}`} />
</td>
<td className="align-middle">
<div className="d-flex flex-row align-items-center">
<Link
data-testid="repoLink"
className="text-dark text-capitalize"
to={{
pathname: '/packages/search',
search: prepareQueryString({
pageNumber: 1,
filters: {
repo: [repoInfo.name],
},
}),
}}
>
{repoInfo.name}
</Link>
</div>
</td>
<td className="align-middle position-relative d-none d-sm-table-cell">
<span className={`mx-1 mb-1 ${styles.tinyIcon}`}>
{repoInfo.userAlias ? <FaUser /> : <MdBusiness />}
</span>{' '}
{repoInfo.userAlias ? (
<Link
data-testid="userLink"
className="text-dark"
to={{
pathname: '/packages/search',
search: prepareQueryString({
pageNumber: 1,
filters: {
user: [repoInfo.userAlias!],
},
}),
}}
>
{repoInfo.userAlias}
</Link>
) : (
<Link
data-testid="orgLink"
className="text-dark"
to={{
pathname: '/packages/search',
search: prepareQueryString({
pageNumber: 1,
filters: {
org: [repoInfo.organizationName!],
},
}),
}}
>
{repoInfo.organizationDisplayName || repoInfo.organizationName}
</Link>
)}
</td>
{REPOSITORY_SUBSCRIPTIONS_LIST.map((subs: SubscriptionItem, index: number) => {
const optItem = item.optOutItems.find((opt: OptOutItem) => subs.kind === opt.eventKind);
return (
<td className="align-middle text-center" key={`td_${repoInfo.name}_${subs.kind}`}>
<div className="text-center position-relative">
<SubscriptionSwitch
repoInfo={repoInfo}
kind={subs.kind}
enabled={subs.enabled}
optOutItem={optItem}
changeSubscription={changeSubscription}
/>
</div>
</td>
);
})}
</tr>
);
})}
{!isUndefined(total) && total > DEFAULT_LIMIT && (
<tr className={styles.paginationCell}>
<td className="align-middle text-center" colSpan={5}>
<Pagination
limit={DEFAULT_LIMIT}
offset={offset}
total={total}
active={activePage}
className="my-3"
onChange={onPageNumberChange}
/>
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
)}
</div>
</div>
{modalStatus && (
<OptOutModal
disabledList={repoIdsList}
optOutList={optOutItems}
onSuccess={getOptOutList}
onClose={() => setModalStatus(false)}
onAuthError={props.onAuthError}
getNotificationTitle={getNotificationTitle}
open
/>
)}
</div>
);
}