office-ui-fabric-react#Text TypeScript Examples
The following examples show how to use
office-ui-fabric-react#Text.
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 azure-serverless-workshop with MIT License | 6 votes |
App: React.FunctionComponent = () => {
return (
<Stack
horizontalAlign="center"
verticalAlign="center"
verticalFill
styles={{
root: {
width: "960px",
margin: "0 auto",
textAlign: "center",
color: "#605e5c",
},
}}
gap={15}>
<Stack.Item align="end">
</Stack.Item>
<Stack.Item align="start">
<Text styles={titleStyle}>
Welcome to Fabrikam Drone Status App
</Text>
</Stack.Item>
<Stack.Item align="start">
<Text styles={descStyle}>
This sample demonstrates how to call a serverless API.
</Text>
</Stack.Item>
<Stack.Item align="start">
<DroneStatusDetailsList />
</Stack.Item>
</Stack>
)
}
Example #2
Source File: index.tsx From azure-serverless-workshop with MIT License | 6 votes |
App: React.FunctionComponent = () => {
return (
<Stack
horizontalAlign="center"
verticalAlign="center"
verticalFill
styles={{
root: {
width: "960px",
margin: "0 auto",
textAlign: "center",
color: "#605e5c",
},
}}
gap={15}>
{auth.handleLoginCallback()}
<Stack.Item align="end">
<LoginActionButton />
</Stack.Item>
<Stack.Item align="start">
<Text styles={titleStyle}>
Welcome to Fabrikam Drone Status App
</Text>
</Stack.Item>
<Stack.Item align="start">
<Text styles={descStyle}>
This sample demonstrates how to authenticate a serverless API.
</Text>
</Stack.Item>
<Stack.Item align="start">
<RestrictedContent />
</Stack.Item>
</Stack>
)
}
Example #3
Source File: Options.tsx From art with MIT License | 6 votes |
export default function Options(props: IProps) {
const selectClasses = useSelectStyles();
return (
<div className="explore__options-box">
<Text style={{ "textAlign": "center", "fontWeight": "bold", "paddingRight": "10px" }} variant="large">Closest</Text>
<FormControl>
<Select
native
value={props.value}
onChange={(event) => { props.changeConditional(event.target.value) }}
classes={{
root: selectClasses.root
}}>
{props.choices.map((choice, index) => (<option key={index} value={choice}>{choice.replace(/_/g, " ")}</option>))}
</Select>
</FormControl>
<Text style={{ "textAlign": "center", "fontWeight": "bold", "paddingLeft": "10px"}} variant="large">Artworks:</Text>
</div>
);
}
Example #4
Source File: Contributors.tsx From website with MIT License | 6 votes |
Contributors = () => {
var theme = useTheme();
const locale = LocalizationService.strings();
//var language: string = LocalizationService.getLanguage();
const contributors: Contributor[] = getContributors();
return (
<div className="pb-4 pt-4" style={{ backgroundColor: theme.palette.neutralLighter }}>
<Container className="contributors text-center">
<div className="mb-4"><Text variant="xLarge">{locale?.contributors.header2}</Text></div>
<div className="contributors mb-2">
<Row className="justify-content-center">
{
contributors.map((x, i) =>
<>
<TooltipHost
content={x.username}
calloutProps={calloutPropsContributor}
styles={hostStyles}
delay={TooltipDelay.zero}
>
<Persona onRenderPrimaryText={() => null} text={x.username} className="mb-1" />
</TooltipHost>
</>
)
}
</Row>
</div>
</Container>
</div>
)
}
Example #5
Source File: DegreeInformations.tsx From website with MIT License | 5 votes |
DegreeInformations= (props: Props) => {
const theme = useTheme();
const locale = LocalizationService.strings();
var language: string | undefined = LocalizationService.getLanguage();
const iconProps: any = { fontSize: '24px' };
const degreeInformations: any[] = getDegreeInformations(props.degree?.slug!);
/* Workaround to not show selected choicegroup */
const [selectedChoiceGroup, setSelectedChoiceGroup] = React.useState<string>("");
const selectionChanged = (ev?: React.FormEvent<HTMLElement | HTMLInputElement>, option?: IChoiceGroupOption): void => { setSelectedChoiceGroup(""); }
const options: IChoiceGroupOption[] = [];
const itemSize = 100;
const choiceGroupOptionsStyle: IChoiceGroupOptionStyles = {
choiceFieldWrapper: {
width: itemSize + "px",
height: itemSize + "px"
},
labelWrapper: {
maxWidth: itemSize / (3 / 4) + "px",
height: "auto",
},
field: {
height: "100%",
padding: "0px"
}
};
degreeInformations?.map((x) => {
return options.push({
key: x.name![language!],
text: x.name![language!],
styles: choiceGroupOptionsStyle,
iconProps: { iconName: x.icon!, className: iconProps, color: theme.palette.themePrimary },
onClick: () => {redirectToLink(x.link!)}
});
});
return (
<div className='degree-informations mb-4'>
<div className="pb-2 pt-2 mb-4" style={{ backgroundColor: theme.palette.neutralLight }}>
<Container>
<div><Text variant="medium" styles={semibold}><Icon iconName="Link12" /> {locale?.groups.availableRedirects}</Text></div>
</Container>
</div>
{
options.length === 0 ? <Message text={locale?.noRedirectsAvailable!} />
:
<div className="text-center justify-content-center" style={{ marginLeft: 'auto', marginRight: 'auto' }}>
<ChoiceGroup options={options} onChange={selectionChanged} selectedKey={selectedChoiceGroup} />
</div>
}
</div>
);
}
Example #6
Source File: ResultArtwork.tsx From art with MIT License | 5 votes |
render() {
var musImg
if (this.props.artwork.Museum === 'rijks') {
musImg = <img style={{ height: '5vh' }} id='musButton2' alt={"The Rijksmuseum Icon"} src={rijksImg} />
} else{
musImg = <img style={{ height: '5vh' }} id='musButton2' alt={"The Met Museum Icon"} src={metImg} />
};
const imgURL = this.props.artwork.Thumbnail_Url;
let dataLoaded = this.props.artwork.id == null ? false : true;
return (
<React.Fragment>
<HideAt breakpoint="mediumAndBelow">
<Stack horizontal horizontalAlign="start" verticalAlign="center" className="explore__main-images">
<Stack>
<Shimmer isDataLoaded={dataLoaded} shimmerElements={[{ type: ShimmerElementType.line, height: 340, width: 300 }]} ariaLabel="loading content">
<div className="explore__artwork-frame">
<Image height={"35vh"} style={{ "maxWidth": "30vw", "objectFit": "cover" }} src={imgURL} className="explore__img" />
<div className="explore__museum-icon">
<TooltipHost delay={TooltipDelay.medium} closeDelay={0} directionalHint={DirectionalHint.bottomCenter} content="View Source" calloutProps={{ gapSpace: 0, target: `#musButton2` }}>
<a href={this.props.artwork.Museum_Page} target="_blank" rel="noopener noreferrer">
{musImg}
</a>
</TooltipHost>
</div>
</div>
</Shimmer>
<Text style={{ "textAlign": "center", "fontWeight": "bold", "paddingTop": "10px" }} variant="large">{"Close Match"}</Text>
</Stack>
<Stack style={{ "marginLeft": 20 }}>
<Text block style={{ "fontWeight": "bold", "width": "15vw" }} variant="xLarge">{this.props.artwork.Title ? this.props.artwork.Title : "Untitled Piece"}</Text>
<Text style={{ "textTransform": "capitalize" }} variant="large">{this.props.artwork.Culture.replace(/_/g, " ")}</Text>
<Text variant="large" style={{ "marginBottom": 15, "textTransform": "capitalize" }}>{this.props.artwork.Classification.replace(/_/g, " ")}</Text>
</Stack>
</Stack>
</HideAt>
<ShowAt breakpoint="mediumAndBelow">
<Stack horizontal horizontalAlign="center" verticalAlign="center" className="explore__main-images">
<Stack>
<div className="explore__img-container">
<Shimmer isDataLoaded={dataLoaded} shimmerElements={[{ type: ShimmerElementType.line, height: 280, width: 230 }]} ariaLabel="loading content">
<div className="explore__artwork-frame">
<Image height={"275px"} style={{ "maxWidth": "100%", "objectFit": "cover" }} src={imgURL} />
<div className="explore__museum-icon">
<TooltipHost delay={TooltipDelay.medium}
closeDelay={0}
directionalHint={DirectionalHint.bottomCenter}
content="View Source"
calloutProps={{ gapSpace: 0, target: `#musButton2` }}>
<a href={this.props.artwork.Museum_Page} target="_blank" rel="noopener noreferrer">
{musImg}
</a>
</TooltipHost>
</div>
</div>
</Shimmer>
</div>
<Text style={{ "textAlign": "center", "fontWeight": "bold" }} variant="large">{"Close Match"}</Text>
</Stack>
</Stack>
</ShowAt>
</React.Fragment>
)
}
Example #7
Source File: QueryArtwork.tsx From art with MIT License | 5 votes |
render() {
let musImg = (this.props.artwork.Museum === 'rijks') ? <img style={{height:'5vh'}} id='musButton1' alt={"The Rijksmuseum Icon"} src={rijksImg} /> : <img style={{height:'5vh'}} id='musButton1' alt={"The Met Museum Icon"} src={metImg} />;
let imgURL = this.props.artwork.Thumbnail_Url;
return (
<React.Fragment>
<HideAt breakpoint="mediumAndBelow">
<Stack horizontal horizontalAlign="end" verticalAlign="center" className="explore__main-images">
<Stack verticalAlign="end" style={{ "marginRight": 20 }}>
<Text block style={{ "textAlign": "right", "fontWeight": "bold" , "width":"15vw"}} variant="xLarge">{this.props.artwork.Title ? this.props.artwork.Title : "Untitled Piece"}</Text>
<Text style={{ "textAlign": "right", "textTransform": "capitalize"}} variant="large">{this.props.artwork.Culture.replace(/_/g, " ")}</Text>
<Text style={{ "textAlign": "right", "marginBottom": 15 , "textTransform": "capitalize"}} variant="large">{this.props.artwork.Classification.replace(/_/g, " ")}</Text>
</Stack>
<Stack>
<div className="explore__artwork-frame" onMouseEnter={() => this.setState({ hover: true })} onMouseLeave={() => this.setState({ hover: false })}>
<Image height={"35vh"} style={{"maxWidth":"30vw", "objectFit":"cover"}} src={imgURL} className="explore__img" />
<div className="explore__museum-icon">
<TooltipHost delay={TooltipDelay.medium} closeDelay={0} directionalHint={DirectionalHint.bottomCenter} content="View Source" calloutProps={{ gapSpace: 0, target: `#musButton1` }}>
<a href={this.props.artwork.Museum_Page} target="_blank" rel="noopener noreferrer">
{musImg}
</a>
</TooltipHost>
</div>
</div>
<Text style={{ "textAlign": "center", "fontWeight": "bold", "paddingTop": "10px" }} variant="large">Query Image</Text>
</Stack>
</Stack>
</HideAt>
<ShowAt breakpoint="mediumAndBelow">
<Stack horizontal horizontalAlign="center" verticalAlign="center" className="explore__main-images">
<Stack onMouseEnter={() => this.setState({ hover: true })} onMouseLeave={() => this.setState({ hover: false })}>
<Stack className="explore__img-container" onMouseEnter={() => this.setState({ hover: true })} onMouseLeave={() => this.setState({ hover: false })}>
<Image height={"275px"} style={{"maxWidth":"100%", "objectFit": "cover"}} src={imgURL} />
<div className="explore__museum-icon">
<TooltipHost delay={TooltipDelay.medium} closeDelay={0} directionalHint={DirectionalHint.bottomCenter} content="View Source" calloutProps={{ gapSpace: 0, target: `#musButton1` }}>
<a href={this.props.artwork.Museum_Page} target="_blank" rel="noopener noreferrer">
{musImg}
</a>
</TooltipHost>
</div>
</Stack>
<Text style={{ "textAlign": "center", "fontWeight": "bold" }} variant="large">Query Image</Text>
</Stack>
</Stack>
</ShowAt>
</React.Fragment>
)
}
Example #8
Source File: CopyMeetingPage.tsx From msteams-meetings-template with MIT License | 5 votes |
function CopyMeetingPageComponent(props: CopyMeetingPageProps) {
return (
<>
<Header />
<Stack
className="container"
verticalFill
tokens={{
childrenGap: 35
}}
>
<Stack.Item align="center" className="meetingCardContainer">
<svg
className="meetingSuccess"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 48 48"
>
<path
d="M24 0c2.2 0 4.3.3 6.4.9 2 .6 3.9 1.4 5.7 2.4 1.8 1 3.4 2.3 4.9 3.8 1.5 1.5 2.7 3.1 3.8 4.9 1 1.8 1.8 3.7 2.4 5.7.6 2 .9 4.2.9 6.4s-.3 4.3-.9 6.3c-.6 2-1.4 3.9-2.4 5.7-1 1.8-2.3 3.4-3.8 4.9-1.5 1.5-3.1 2.7-4.9 3.8-1.8 1-3.7 1.9-5.7 2.4-2 .6-4.1.9-6.4.9-2.2 0-4.3-.3-6.3-.9-2-.6-3.9-1.4-5.7-2.4-1.8-1-3.4-2.3-4.9-3.8-1.5-1.5-2.7-3.1-3.8-4.9-1-1.8-1.9-3.7-2.4-5.7C.3 28.3 0 26.2 0 24s.3-4.3.9-6.4c.6-2 1.4-3.9 2.4-5.7 1-1.8 2.3-3.4 3.8-4.9 1.5-1.5 3.1-2.7 4.9-3.8 1.8-1 3.7-1.9 5.7-2.4S21.8 0 24 0zm7.9 17.1c-.6 0-1.2.2-1.6.7l-8.5 8.5-3-3c-.4-.4-1-.7-1.6-.7-.3 0-.6.1-.8.2-.3.1-.5.3-.7.5s-.4.4-.5.7c-.2.3-.2.5-.2.8 0 .6.2 1.2.7 1.6l4.6 4.6c.4.4 1 .7 1.6.7.6 0 1.2-.2 1.6-.7l10.1-10.1c.4-.5.7-1 .7-1.6 0-.3-.1-.6-.2-.8-.1-.3-.3-.5-.5-.7s-.4-.4-.7-.5c-.4-.2-.7-.2-1-.2z"
fill="#599c00"
/>
</svg>
<Text block variant="xLarge" className="meetingCardHeader">
<FormattedMessage id="copyMeetingPage.header" />
</Text>
<div
className="meetingCardBody"
id="copy"
dangerouslySetInnerHTML={{ __html: props.meeting?.preview ?? '' }}
/>
<PrimaryButton
className="teamsButton copyButton"
onClick={() => props.onCopyToClipboard(props.meeting)}
ariaLabel={translate('copyMeetingPage.copy.ariaLabel')}
>
<FormattedMessage id="copyMeetingPage.copy" />
</PrimaryButton>
</Stack.Item>
</Stack>
</>
);
}
Example #9
Source File: AdminsList.tsx From website with MIT License | 5 votes |
AdminsList = (props: Props) => {
var theme = useTheme();
const locale = LocalizationService.strings();
let [admins, setAdmins] = React.useState<Admin[]>([]); // Amministratori
const [loadingAdmins, setLoadingAdmins] = React.useState<boolean>(false);
const [errorLoadingAdmins, setErrorLoadingAdmins] = React.useState<boolean>(false);
/* Admins callBack */
const updateAdmins = React.useCallback(async () => {
if (props.degree?.slug === '' || props.degree?.slug === undefined) return;
setErrorLoadingAdmins(false);
setLoadingAdmins(true);
let adminsResult = await getDegreeAdmins(props.degree?.slug);
if (adminsResult.status !== 200) {
setLoadingAdmins(false);
setErrorLoadingAdmins(true);
return;
}
setLoadingAdmins(false);
setAdmins(adminsResult.value ?? []);
}, [props.degree?.slug]);
React.useEffect(() => {
updateAdmins();
}, [props.degree, updateAdmins]);
return (
<div className="mb-2">
<div className="pb-2 pt-2 mb-4" style={{ backgroundColor: theme.palette.neutralLight }}>
<Container>
<div><Text variant="medium" styles={semibold}><Icon iconName="WorkforceManagement" /> {locale?.groups.availableAdmins}</Text></div>
</Container>
</div>
{
loadingAdmins || errorLoadingAdmins ? <LoadingSpinner loading={loadingAdmins} error={errorLoadingAdmins} />
: admins.length === 0 ?
<div className="justify-content-center">
<Message text={locale?.groups.adminsNotFound!} />
</div> : <></>
}
{admins.length !== 0 && !errorLoadingAdmins && !loadingAdmins ?
<Container>
<Row className="admin-list" style={{ justifyContent: admins?.length === 0 ? 'center' : ""}}>
{admins?.length !== 0 ? admins?.map((x,i) =>
<Col key={i} xl={3} lg={3} md={4} sm={6} xs={12} className="mb-3 col-persona">
{(() => {
var imageUrl = `https://studentiunimi-groups-propics.marcoaceti.workers.dev/${x.id}.png`;
return <Persona imageUrl={imageUrl} onRenderPrimaryText={() => (<><Icon iconName="Send" style={{ color: theme.palette.themePrimary }}/> <Link href={`https://t.me/${x.username}`}>{`${x.first_name ?? ""} ${x.last_name ?? ""}`}</Link></>)} text={`@${x.first_name ?? ""} ${x.last_name ?? ""}`} secondaryText={`@${x.username}`} size={PersonaSize.size40} />
})()}
</Col>
) : <Message text={locale?.groups.adminsNotFound!} />
}
</Row>
</Container> : <></>
}
</div>
)
}
Example #10
Source File: AdditionalGroup.tsx From website with MIT License | 5 votes |
AdditionalGroup = (props: Props) => {
const theme = useTheme();
const locale = LocalizationService.strings();
var language: string | undefined = LocalizationService.getLanguage();
const data = props.data;
const helpfulTextStyles: ITextStyles = { root: { fontWeight: FontWeights.regular, } };
const descriptionTextStyles: ITextStyles = { root: { fontWeight: FontWeights.semibold } };
const cardTokens: ICardTokens = { childrenMargin: 12 };
const telegramGroupIcon: IIconProps = { iconName: 'Send' };
let desc = data.description![language!];
let name = data.name![language!];
// PrimaryText inizialization
var primaryText : any;
primaryText = <div style={{ wordWrap: 'break-word', whiteSpace: 'normal', marginTop: '2px' }}><Text styles={semibold}>{name}</Text></div>;
// Group image initialization
var imageUrl: string;
imageUrl = process.env.PUBLIC_URL + '/extra_groups_images/' + data.image;
return (
<Card tokens={cardTokens}>
<Card.Item>
<Persona imageUrl={imageUrl} onRenderPrimaryText={() => primaryText} text={name} />
</Card.Item>
<Card.Section>
<Text styles={descriptionTextStyles}>
<Chip label={name === 'MUG - Milan University Gamers' ? locale?.studentsAssociation : locale?.extraGroups.extraGroup} size="small" style={{ color: theme.palette.white, backgroundColor: name === 'MUG - Milan University Gamers' ? theme.palette.themeTertiary : theme.palette.themeSecondary }} className="m-1" />
</Text>
<Text variant="small" styles={helpfulTextStyles} className="mb-2">
<JsxParser bindings={{ theme: theme, semibold: semibold }} components={{ Text, Link, Icon }} jsx={"<Icon iconName='Info' /> " + desc} />
</Text>
{
(() => {
if (data.gruppo !== "" && data.gruppo !== null) {
return (
<ActionButton
href={data.gruppo as any}
className="text-decoration-none"
iconProps={telegramGroupIcon}
style={{ justifyContent: 'center', marginLeft: 'auto', marginRight: 'auto', marginTop: '3px' }}
disabled={data.gruppo === "" || data.gruppo === null}
allowDisabledFocus>
{name === 'MUG - Milan University Gamers' ? locale?.homepage.section3.part3.title : locale?.telegramGroup}
</ActionButton>
);
}
})()
}
</Card.Section>
</Card>
);
}
Example #11
Source File: Mantainers.tsx From website with MIT License | 5 votes |
Mantainers = () => {
var theme = useTheme();
const locale = LocalizationService.strings();
var language: string | undefined = LocalizationService.getLanguage();
const profileIconStyle = { color: theme.palette.themePrimary, fontSize: FontSizes.size24 };
const sectionCard = {
minHeight: '120px',
height: '100%',
width: '100%',
maxWidth: 'none',
marginLeft: 'auto',
marginRight: 'auto',
maxHeight: 'none',
backgroundColor: theme.palette.white
};
return (
<div className="pb-4 pt-4" style={{ backgroundColor: theme.palette.neutralLighter }}>
<Container className="contributors text-center">
<div className="mb-4"><Text variant="xLarge">{locale?.contributors.header1}</Text></div>
<Row className="justify-content-center">
{
developers.map((x: any, i: any) => {
return (
<Col className="mb-3" xl={4} lg={4} md={4} sm={6} xs={12} key={i}>
<Card tokens={cardTokens} style={sectionCard} className="justify-content-center text-center">
<Card.Section>
<div className="justify-content-center">
<Image id="logo"
src={process.env.PUBLIC_URL + "/contributors/" + x.pic}
alt={x.name}
style={developerPic}
/>
</div>
<div className="mb-0"><Text variant="medium" styles={semibold}>{x.name}</Text></div>
<Text variant="medium" className="mt-2">
{x.description[language!]}
</Text>
<div>
<TooltipHost
content={locale?.contributors.githubProfile}
calloutProps={calloutProps}
styles={hostStyles}
delay={TooltipDelay.zero}
>
<Link onClick={() => redirectToLink(x.github)}><Icon iconName="ProfileSearch" style={profileIconStyle} /></Link>
</TooltipHost>
<TooltipHost
content={locale?.contributors.websiteProfile}
calloutProps={calloutProps}
styles={hostStyles}
delay={TooltipDelay.zero}
>
<Link onClick={() => redirectToLink(x.website)}><Icon iconName="Website" style={profileIconStyle} /></Link>
</TooltipHost>
</div>
</Card.Section>
</Card>
</Col>
)
})
}
</Row>
</Container>
</div>
)
}
Example #12
Source File: SigninPage.tsx From msteams-meetings-template with MIT License | 5 votes |
function SigninPageComponent(props: Partial<SigninPageProps>) {
const onSignIn = props.onSignIn ?? (() => {});
return (
<>
<div className="microsoftLogo">
<svg xmlns="http://www.w3.org/2000/svg" width="108" height="24">
<path
d="M44.836 4.6v13.8h-2.4V7.583H42.4L38.119 18.4h-1.588L32.142 7.583h-.029V18.4H29.9V4.6h3.436L37.3 14.83h.058L41.545 4.6zm2 1.049a1.268 1.268 0 01.419-.967 1.413 1.413 0 011-.39 1.392 1.392 0 011.02.4 1.3 1.3 0 01.4.958 1.248 1.248 0 01-.414.953 1.428 1.428 0 01-1.01.385A1.4 1.4 0 0147.25 6.6a1.261 1.261 0 01-.409-.948M49.41 18.4h-2.329V8.507h2.329zm7.064-1.694a3.213 3.213 0 001.145-.241 4.811 4.811 0 001.155-.635V18a4.665 4.665 0 01-1.266.481 6.886 6.886 0 01-1.554.164 4.707 4.707 0 01-4.918-4.908 5.641 5.641 0 011.4-3.932 5.055 5.055 0 013.955-1.545 5.414 5.414 0 011.324.168 4.431 4.431 0 011.063.39v2.233a4.763 4.763 0 00-1.1-.611 3.184 3.184 0 00-1.15-.217 2.919 2.919 0 00-2.223.9 3.37 3.37 0 00-.847 2.416 3.216 3.216 0 00.813 2.338 2.936 2.936 0 002.209.837m8.92-8.371a2.952 2.952 0 01.5.039 2.1 2.1 0 01.375.1v2.358a2.04 2.04 0 00-.534-.255 2.646 2.646 0 00-.852-.12 1.808 1.808 0 00-1.448.722 3.467 3.467 0 00-.592 2.223v4.99h-2.324V8.507h2.329v1.559h.038a2.729 2.729 0 01.963-1.266 2.611 2.611 0 011.545-.457m1 5.254a5.358 5.358 0 011.392-3.887 5.1 5.1 0 013.85-1.434 4.742 4.742 0 013.623 1.381 5.212 5.212 0 011.3 3.729 5.257 5.257 0 01-1.386 3.83 5.019 5.019 0 01-3.772 1.424 4.935 4.935 0 01-3.652-1.352 4.987 4.987 0 01-1.349-3.688m2.425-.077a3.535 3.535 0 00.7 2.368 2.505 2.505 0 002.011.818 2.345 2.345 0 001.934-.818 3.783 3.783 0 00.664-2.425 3.651 3.651 0 00-.688-2.411 2.389 2.389 0 00-1.929-.813 2.44 2.44 0 00-1.988.852 3.707 3.707 0 00-.707 2.43m11.2-2.416a1 1 0 00.318.785 5.426 5.426 0 001.4.717 4.767 4.767 0 011.959 1.256 2.6 2.6 0 01.563 1.689 2.715 2.715 0 01-1.068 2.239 4.558 4.558 0 01-2.9.847 6.978 6.978 0 01-1.362-.149 6.047 6.047 0 01-1.265-.38v-2.29a5.733 5.733 0 001.367.7 4 4 0 001.328.26 2.365 2.365 0 001.164-.221.79.79 0 00.375-.741 1.029 1.029 0 00-.39-.813 5.768 5.768 0 00-1.477-.765 4.564 4.564 0 01-1.829-1.213 2.655 2.655 0 01-.539-1.713 2.706 2.706 0 011.063-2.2 4.243 4.243 0 012.765-.86 6.663 6.663 0 011.164.115 5.161 5.161 0 011.078.3v2.214a4.974 4.974 0 00-1.078-.529 3.6 3.6 0 00-1.222-.221 1.781 1.781 0 00-1.034.26.824.824 0 00-.371.712m5.241 2.493a5.358 5.358 0 011.386-3.89 5.1 5.1 0 013.849-1.434 4.743 4.743 0 013.624 1.381 5.212 5.212 0 011.3 3.729 5.259 5.259 0 01-1.386 3.83 5.02 5.02 0 01-3.773 1.424 4.934 4.934 0 01-3.652-1.352 4.987 4.987 0 01-1.348-3.688m2.425-.077a3.537 3.537 0 00.7 2.368 2.506 2.506 0 002.011.818 2.345 2.345 0 001.934-.818 3.783 3.783 0 00.664-2.425 3.651 3.651 0 00-.688-2.411 2.39 2.39 0 00-1.93-.813 2.439 2.439 0 00-1.987.852 3.707 3.707 0 00-.707 2.43m15.464-3.109H99.7V18.4h-2.359v-7.988h-1.655V8.507h1.655V7.13a3.423 3.423 0 011.015-2.555 3.561 3.561 0 012.6-1 5.807 5.807 0 01.751.043 2.993 2.993 0 01.577.13v2.016a2.422 2.422 0 00-.4-.164 2.107 2.107 0 00-.664-.1 1.407 1.407 0 00-1.126.457 2.017 2.017 0 00-.394 1.356v1.194h3.469V6.283l2.339-.712v2.936h2.358v1.906h-2.358v4.629a1.951 1.951 0 00.332 1.29 1.326 1.326 0 001.044.375 1.557 1.557 0 00.486-.1 2.294 2.294 0 00.5-.231V18.3a2.737 2.737 0 01-.736.231 5.029 5.029 0 01-1.015.106 2.887 2.887 0 01-2.209-.784 3.341 3.341 0 01-.736-2.363z"
fill="#737373"
/>
<path fill="#f25022" d="M0 0h10.931v10.931H0z" />
<path fill="#7fba00" d="M12.069 0H23v10.931H12.069z" />
<path fill="#00a4ef" d="M0 12.069h10.931V23H0z" />
<path fill="#ffb900" d="M12.069 12.069H23V23H12.069z" />
</svg>
</div>
<Stack
className="container"
horizontalAlign="center"
verticalAlign="center"
verticalFill
tokens={{
childrenGap: 35
}}
>
<img
className="splashImage"
src={signInImage}
alt={translate('signin.logo')}
/>
<Text variant="xLargePlus" styles={boldStyle} className="signinHeader">
<FormattedMessage id="signin.header" />
</Text>
<Text variant="medium" className="uTextCenter signinSubHeader">
<FormattedMessage id="signin.subheader.lead" />
</Text>
<Text variant="medium" className="uTextCenter signinSubHeader">
<FormattedMessage id="signin.subheader.signin" />
</Text>
<PrimaryButton
className="teamsButton"
onClick={() => onSignIn()}
ariaLabel={translate('signin.button.ariaLabel')}
>
<FormattedMessage id="signin.button" />
</PrimaryButton>
</Stack>
</>
);
}
Example #13
Source File: ErrorPage.tsx From msteams-meetings-template with MIT License | 5 votes |
function ErrorPageComponent(props: ErrorPageProps) {
return (
<>
<Header />
<Stack
className="container"
horizontalAlign="center"
verticalAlign="center"
verticalFill
tokens={{
childrenGap: 35
}}
>
<img
className="splashImage"
src={errorImage}
alt={translate('errorPage.splash.altText')}
/>
<Text variant="xLargePlus" styles={boldStyle}>
<FormattedMessage id="errorPage.heading" />
</Text>
<Text variant="medium" className="uTextCenter">
<FormattedMessage id="errorPage.subheading" />
</Text>
<Stack horizontal tokens={{ childrenGap: 10 }}>
<DefaultButton
className="teamsButtonInverted"
onClick={() => props.goBack()}
ariaLabel={translate('errorPage.back.ariaLabel')}
>
<FormattedMessage id="errorPage.back" />
</DefaultButton>
<PrimaryButton
className="teamsButton"
onClick={() => props.retryCreateMeeting(props.meeting)}
ariaLabel={translate('errorPage.try.again')}
>
<FormattedMessage id="errorPage.try.again" />
</PrimaryButton>
</Stack>
</Stack>
</>
);
}
Example #14
Source File: CreateLandingPage.tsx From msteams-meetings-template with MIT License | 5 votes |
function CreateLandingPageComponent(props: CreateLandingPageProps) {
// Check for a signed-in user and go to the signin page if there isn't one
const checkForSignedInUser = props.checkForSignedInUser;
React.useEffect(() => {
checkForSignedInUser();
});
return (
<>
<Header />
<Stack
className="container"
horizontalAlign="center"
verticalAlign="center"
verticalFill
tokens={{
childrenGap: 35
}}
>
<img
className="splashImage"
src={calendar}
alt={translate('createLandingPage.splash.altText')}
/>
<Text variant="xLargePlus" styles={boldStyle}>
<FormattedMessage id="createLandingPage.schedule.header" />
</Text>
<Text variant="medium">
<FormattedMessage id="createLandingPage.subheader" />
</Text>
<PrimaryButton
className="teamsButton"
onClick={() => props.onNewMeeting()}
ariaLabel={translate('createLandingPage.create.meeting.ariaLabel')}
>
<FormattedMessage id="createLandingPage.create.meeting" />
</PrimaryButton>
</Stack>
</>
);
}
Example #15
Source File: Footer.tsx From website with MIT License | 4 votes |
Footer = (props: Props) => {
var theme = useTheme();
const [cookies, setCookie] = useCookies();
const locale = LocalizationService.strings();
var language: string | undefined = LocalizationService.getLanguage();
const date: Date = addDays(new Date(), 90);
const themeToggled = () => {
if (cookies["theme"] === "dark") setCookie("theme", "light", { path: "/", expires: date });
else { setCookie("theme", "dark", { path: "/", expires: date }); }
props.changeTheme();
};
const changeLanguage = (lang: string) => {
LocalizationService.localize(lang);
setCookie("language", lang, { path: "/", expires: date });
props.changeLanguage(lang);
};
const wrapIconStyle = { backgroundColor: theme.palette.themeSecondary, borderRadius: '35%', minWidth: 30, minHeight: 30, display: 'inline-block', textAlign: 'center', justifyContent: 'center', verticalAlign: 'middle' } as React.CSSProperties;
const iconStyle = { color: theme.palette.white, fontSize: '17px', marginTop: 6 };
const buttonStyle = { maxWidth: '270px', boxShadow: theme.effects.elevation8 };
const buttonIconProps: IIconProps = { iconName: 'ChevronRightSmall', styles: { root: { fontSize: 12 } } };
/* Theme palette code */
const colorCells: any[] = palettes.map(x => ({ id: x.id, label: x.label, color: x.palette?.themePrimary }));
const resetColorIcon: IIconProps = { iconName: 'SyncOccurence' };
const calloutPropsResetColor = { gapSpace: 10 };
const hostStylesResetColor: Partial<ITooltipHostStyles> = { root: { display: 'inline-block' } };
return (
<footer style={{ backgroundColor: theme.palette.neutralQuaternaryAlt, borderTop: '1px solid', borderColor: theme.palette.neutralLight }} className="pt-4 pb-4">
<Container style={{ width: '100%', color: theme.palette.neutralSecondary }}>
<Row className="mb-4">
<Col xl={4} lg={4} md={6} sm={12} xs={12} className="mb-4 mb-md-0">
<div className="mb-2">
<Text styles={semibold} style={{ color: theme.palette.themePrimary }} variant="large">
© Network StudentiUniMi
</Text>
</div>
<div className="mb-2 text">
<PrimaryButton text={locale?.footer[0].buttonText} iconProps={buttonIconProps} href="https://t.me/unimichat" className="text-decoration-none" allowDisabledFocus style={buttonStyle} />
</div>
</Col>
<Col xl={2} lg={2} md={3} sm={12} xs={12} className="mb-2 mb-md-0">
<div>
<div className="mb-2">
<Text styles={semibold} variant="medium">{locale?.footer[1].header}</Text>
</div>
<div>
<Text variant="medium">
<ul className="list-unstyled mb-3">
<li style={listElement}>
<Link href="http://www.quickunimi.it/">QuickUnimi</Link>
</li>
<li style={listElement}>
<Link href="https://codeshare.tech">Codeshare.tech</Link>
</li>
</ul>
</Text>
</div>
</div>
</Col>
<Col xl={3} lg={2} md={3} sm={12} xs={12}>
<div className="mb-2">
<Toggle
label={locale?.settingsPanel.changeTheme}
onText={locale?.settingsPanel.darkTheme}
offText={locale?.settingsPanel.lightTheme}
checked={cookies["theme"] === "dark"}
onChange={themeToggled}
theme={theme}
/>
</div>
<div className="mb-2 language-selector">
<Label>{locale?.settingsPanel.selectLanguage}</Label>
<Text
variant="medium"
style={{ cursor: 'pointer' }}
styles={cookies["language"] === "it" ? bold : {}} onClick={() => { changeLanguage("it") } }
>
ITA
</Text>
<Text variant="medium"> | </Text>
<Text
variant="medium"
style={{ cursor: 'pointer' }}
styles={cookies["language"] === "en" ? bold : {}} onClick={() => { changeLanguage("en") }}
>
ENG
</Text>
</div>
</Col>
<Col xl={3} lg={4} md={6} sm={12} xs={12}>
<div>
<Text variant="medium" styles={semibold}>{locale?.settingsPanel.selectColor} </Text>
<TooltipHost
content="Reset color"
calloutProps={calloutPropsResetColor}
styles={hostStylesResetColor}
>
<IconButton iconProps={resetColorIcon} onClick={() => { setCookie("palette", 'a', { path: "/", expires: date }); props.changePalette('a'); }} />
</TooltipHost>
<SwatchColorPicker selectedId={cookies["palette"]} columnCount={7} cellShape={'square'} colorCells={colorCells} onColorChanged={(id) => { setCookie("palette", id, { path: "/", expires: date }); props.changePalette(id!); }} />
</div>
</Col>
</Row>
<Row>
<Col lg={6} sm={12} style={{ display: 'table' }} className="center-mobile mb-2">
<Text variant="medium" style={{ display: 'table-cell', verticalAlign: 'middle' }}>
{locale?.footer[0].text}
</Text>
</Col>
<Col lg={6} sm={12}>
<div className="mb-1 text-right center-mobile">
{footerIcons.map( (x: any, i: number) => {
return (
<TooltipHost
content={x.name[language!]}
calloutProps={calloutPropsResetColor}
styles={hostStylesResetColor}
key={i}
delay={TooltipDelay.zero}
>
<Link href={x.link}>
<span style={wrapIconStyle} className="text-decoration mr-1">
{ x.type === 'brand' ?
<FontAwesomeIcon icon={['fab', x.iconName]} style={iconStyle} />
:
<FontAwesomeIcon icon={x.iconName} style={iconStyle} /> }
</span>
</Link>
</TooltipHost>
)}
)}
</div>
</Col>
</Row>
</Container>
</footer>
)
}
Example #16
Source File: header.tsx From msteams-meetings-template with MIT License | 4 votes |
function HeaderComponent(props: Partial<HeaderProps>) {
const onSignOut = props.onSignOut ?? (() => {});
return (
<div className="header">
<div className="headerLogo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2228.833 2073.333">
<path
fill="#5059C9"
d="M1554.637 777.5h575.713c54.391 0 98.483 44.092 98.483 98.483v524.398c0 199.901-162.051 361.952-361.952 361.952h-1.711c-199.901.028-361.975-162-362.004-361.901V828.971c.001-28.427 23.045-51.471 51.471-51.471z"
/>
<circle fill="#5059C9" cx="1943.75" cy="440.583" r="233.25" />
<circle fill="#7B83EB" cx="1218.083" cy="336.917" r="336.917" />
<path
fill="#7B83EB"
d="M1667.323 777.5H717.01c-53.743 1.33-96.257 45.931-95.01 99.676v598.105c-7.505 322.519 247.657 590.16 570.167 598.053 322.51-7.893 577.671-275.534 570.167-598.053V877.176c1.245-53.745-41.268-98.346-95.011-99.676z"
/>
<path
opacity=".1"
d="M1244 777.5v838.145c-.258 38.435-23.549 72.964-59.09 87.598a91.856 91.856 0 01-35.765 7.257H667.613c-6.738-17.105-12.958-34.21-18.142-51.833a631.287 631.287 0 01-27.472-183.49V877.02c-1.246-53.659 41.198-98.19 94.855-99.52H1244z"
/>
<path
opacity=".2"
d="M1192.167 777.5v889.978a91.838 91.838 0 01-7.257 35.765c-14.634 35.541-49.163 58.833-87.598 59.09H691.975c-8.812-17.105-17.105-34.21-24.362-51.833-7.257-17.623-12.958-34.21-18.142-51.833a631.282 631.282 0 01-27.472-183.49V877.02c-1.246-53.659 41.198-98.19 94.855-99.52h475.313z"
/>
<path
opacity=".2"
d="M1192.167 777.5v786.312c-.395 52.223-42.632 94.46-94.855 94.855h-447.84A631.282 631.282 0 01622 1475.177V877.02c-1.246-53.659 41.198-98.19 94.855-99.52h475.312z"
/>
<path
opacity=".2"
d="M1140.333 777.5v786.312c-.395 52.223-42.632 94.46-94.855 94.855H649.472A631.282 631.282 0 01622 1475.177V877.02c-1.246-53.659 41.198-98.19 94.855-99.52h423.478z"
/>
<path
opacity=".1"
d="M1244 509.522v163.275c-8.812.518-17.105 1.037-25.917 1.037-8.812 0-17.105-.518-25.917-1.037a284.472 284.472 0 01-51.833-8.293c-104.963-24.857-191.679-98.469-233.25-198.003a288.02 288.02 0 01-16.587-51.833h258.648c52.305.198 94.657 42.549 94.856 94.854z"
/>
<path
opacity=".2"
d="M1192.167 561.355v111.442a284.472 284.472 0 01-51.833-8.293c-104.963-24.857-191.679-98.469-233.25-198.003h190.228c52.304.198 94.656 42.55 94.855 94.854z"
/>
<path
opacity=".2"
d="M1192.167 561.355v111.442a284.472 284.472 0 01-51.833-8.293c-104.963-24.857-191.679-98.469-233.25-198.003h190.228c52.304.198 94.656 42.55 94.855 94.854z"
/>
<path
opacity=".2"
d="M1140.333 561.355v103.148c-104.963-24.857-191.679-98.469-233.25-198.003h138.395c52.305.199 94.656 42.551 94.855 94.855z"
/>
<linearGradient
id="a"
gradientUnits="userSpaceOnUse"
x1="198.099"
y1="1683.073"
x2="942.234"
y2="394.261"
gradientTransform="matrix(1 0 0 -1 0 2075.333)"
>
<stop offset="0" style={{ stopColor: '#5a62c3' }} />
<stop offset=".5" style={{ stopColor: '#4d55bd' }} />
<stop offset="1" style={{ stopColor: '#3940ab' }} />
</linearGradient>
<path
fill="url(#a)"
d="M95.01 466.5h950.312c52.473 0 95.01 42.538 95.01 95.01v950.312c0 52.473-42.538 95.01-95.01 95.01H95.01c-52.473 0-95.01-42.538-95.01-95.01V561.51c0-52.472 42.538-95.01 95.01-95.01z"
/>
<path
fill="#FFF"
d="M820.211 828.193h-189.97v517.297h-121.03V828.193H320.123V727.844h500.088v100.349z"
/>
</svg>
</div>
<div>
<Text variant="xLarge" styles={boldStyle}>
Microsoft Teams
</Text>
</div>
<div className="headerIcon">
<IconButton
onClick={() => onSignOut()}
iconProps={{ iconName: 'Leave' }}
title={translate('header.signout.title')}
ariaLabel={translate('header.signout.ariaLabel')}
/>
</div>
</div>
);
}
Example #17
Source File: GroupItem.tsx From website with MIT License | 4 votes |
CourseItem = (props: Props) => {
const theme = useTheme();
const locale = LocalizationService.strings();
let data = props.data;
const cfuStyle: ITextStyles = { root: { fontWeight: FontWeights.semibold, color: theme.palette.themePrimary } };
const descriptionTextStyles: ITextStyles = { root: { fontWeight: FontWeights.semibold } };
const cardTokens: ICardTokens = { childrenMargin: 12 };
const websiteIcon: IIconProps = { iconName: 'Globe' };
const telegramGroupIcon: IIconProps = { iconName: 'Send' };
const wikiIcon: IIconProps = { iconName: 'SurveyQuestions' };
var primaryText : any;
var overflow : boolean = false;
var cfuText : any;
var yearText : any;
var semesterText : any;
var mainText : any;
// PrimaryText inizialization
const courseNameLength: number | undefined = data.course?.name?.length;
if (courseNameLength !== undefined && courseNameLength >= 33) {
primaryText = <Text styles={semibold}>{data.course?.name}</Text>;
} else {
overflow = true;
primaryText = <div style={{ wordWrap: 'break-word', whiteSpace: 'normal', marginTop: '2px' }}><Text styles={semibold}>{data.course?.name}</Text></div>;
}
// PersonaUrl inizialization
let personaIconUrl: string | undefined;
/*
if (data.year === -1) personaIconUrl = process.env.PUBLIC_URL + `/degree_groups_images/unimi.jpg`;
//if (data.year === -1) personaIconUrl = process.env.PUBLIC_URL + `/degree_groups_images/${data.cdl}150.jpg`;
*/
personaIconUrl = `https://studentiunimi-groups-propics.marcoaceti.workers.dev/${data.course?.group?.id}.png`;
/* CFU inizialization */
switch (data.course?.cfu) {
case 0:
cfuText = null;
break;
case null:
cfuText = null;
break;
case undefined:
cfuText = <>N/A CFU</>;
break;
default:
cfuText = <>{data.course?.cfu} CFU</>;
break;
}
/* Year inizialization */
switch (data?.year) {
case 0: /* Insegnamento di un corso di laurea senza anno */
yearText = null;
break;
case -1: /* Gruppo principale */
yearText = null;
break;
case -2: /* Complementare */
yearText = <span>{locale?.groups.complementary}</span>;
break;
case undefined: /* Errore o non disponibile */
yearText = <span>N/A</span>;
break;
default:
yearText = <span>{data.year}° {locale?.groups.year}</span>;
break;
}
/* Semester inizialization */
if (data.semester === -1 || data.semester === null || data.semester === 0) {
semesterText = null;
} else if (data.semester === undefined) {
semesterText = <span>N/A</span>;
} else if (data.semester !== null) {
semesterText = <span>{data.semester}° {locale?.groups.semester}</span>;
}
// Main text inizialization
if (data.year === -1) {
if (ITgroupsIDs.indexOf(data.course?.group?.id!) !== -1) {
mainText = <JsxParser bindings={{ theme: theme, semibold: semibold }} components={{ Text, Link }} jsx={locale?.groups.tutorsGroupDescription} />;
} else {
mainText = locale?.groups.mainGroupDescription;
}
}
/* Telegram Group initialization */
const telegramLink = () => {
if (data.course?.group !== null && data.course?.group !== undefined) {
if (data.course?.group?.invite_link !== "" && data.course?.group?.invite_link !== null && data.course?.group?.invite_link !== undefined) {
return (
<ActionButton
href={data.course?.group?.invite_link as any}
iconProps={telegramGroupIcon}
style={{ justifyContent: 'center', marginLeft: 'auto', marginRight: 'auto', marginTop: '3px' }}
disabled={data.course?.group?.invite_link === "" || data.course?.group?.invite_link === null}
className="text-decoration-none"
allowDisabledFocus>
{locale?.telegramGroup}
</ActionButton>
);
} else if ((data.course?.group?.invite_link === undefined || data.course?.group?.invite_link === "" || data.course?.group?.invite_link === null)) {
return (
<ActionButton
iconProps={telegramGroupIcon}
style={{ justifyContent: 'center', marginLeft: 'auto', marginRight: 'auto', marginTop: '3px' }}
disabled
allowDisabledFocus>
{locale?.groups.groupNotAvailable}
</ActionButton>
);
}
} else return (
<ActionButton
iconProps={telegramGroupIcon}
style={{ justifyContent: 'center', marginLeft: 'auto', marginRight: 'auto', marginTop: '3px' }}
disabled
allowDisabledFocus>
{locale?.groups.groupNotAvailable}
</ActionButton>
)
};
/* Websites inizialization */
let websites: any[] | undefined = [];
if ((data.course?.links ?? []).length !== 0) {
websites = data.course?.links.map(
(e, i) => {
return {
key: i,
text: e.name,
onClick: () => redirectToLink(e.url!),
iconProps: { iconName: 'ChromeBackMirrored' }
};
}
);
}
/* Wiki initialization */
const wikiLink = () => {
if (data.course?.wiki_link !== null && data.course?.wiki_link !== "") {
return (
<ActionButton
href={data.course?.wiki_link as any}
className="text-decoration-none"
iconProps={wikiIcon}
style={{ justifyContent: 'center', marginLeft: 'auto', marginRight: 'auto', marginTop: 0 }}
allowDisabledFocus>
Wiki
</ActionButton>
);
} else if ((data.course?.wiki_link === null || data.course?.wiki_link === "") && data.year !== -1) return (
<ActionButton
disabled
iconProps={wikiIcon}
style={{ justifyContent: 'center', marginLeft: 'auto', marginRight: 'auto', marginTop: 0 }}
allowDisabledFocus>
Wiki
</ActionButton>
)
};
const menuProps: IContextualMenuProps = {
// For example: disable dismiss if shift key is held down while dismissing
onDismiss: ev => {
if (ev && 'shiftKey' in ev) {
ev.preventDefault();
}
},
items: websites as any[],
directionalHintFixed: true,
};
return (
<Card tokens={cardTokens} className="text-center">
<Card.Item>
{overflow === true ?
<Persona imageUrl={personaIconUrl} onRenderPrimaryText={() => primaryText} text={data.course?.name} />
:
<Persona imageUrl={personaIconUrl} text={data.course?.name} />
}
</Card.Item>
<Card.Section>
<Text variant="small" styles={cfuStyle}>
{cfuText}
</Text>
<Text styles={descriptionTextStyles}>
{data.year === -1 ? <Chip label={locale?.groups.mainGroup} size="small" style={{ color: theme.palette.white, backgroundColor: theme.palette.themeTertiary }} className="m-1" /> : <></>}
{yearText !== "" && yearText !== null ? <Chip label={yearText} size="small" style={{ color: theme.palette.white, backgroundColor: theme.palette.themeSecondary }} className="m-1" /> : <></>}
{semesterText !== "" && semesterText !== null ? <Chip label={semesterText} size="small" style={{ color: theme.palette.white, backgroundColor: theme.palette.themeSecondary }} /> : <></>}
</Text>
<Text variant="small" style={{ marginTop: '10px', marginBottom: '10px' }}>
{mainText}
</Text>
{ telegramLink() }
{ data.year !== -1 ?
<CommandButton
text={locale?.groups.websites}
style={{justifyContent: 'center', marginLeft: 'auto', marginRight: 'auto', marginTop: 0}}
iconProps={websiteIcon}
menuProps={menuProps}
allowDisabledFocus
disabled={websites?.length === 0}
/> : <></>
}
{ wikiLink() }
</Card.Section>
</Card>
);
}
Example #18
Source File: GroupsView.tsx From website with MIT License | 4 votes |
GroupsView = () => {
var theme = useTheme();
const locale = LocalizationService.strings();
var language: string | undefined = LocalizationService.getLanguage();
let history = useHistory();
let didMount = React.useRef(false);
const resetIcon: IIconProps = { iconName: 'Refresh' };
const calloutProps = { gapSpace: 10 };
const hostStyles: Partial<ITooltipHostStyles> = { root: { display: 'inline-block' } };
/* States */
let [hideApiErrorDialog, { toggle: toggleApiErrorDialog }] = useBoolean(true);
let [degreeTextSearch, setDegreeTextSearch] = React.useState(''); // Testo nel campo di ricerca
let [loadedDegree, setLoadedDegree] = React.useState<VerboseDegree | null>(null); // Degree da passare ai vari componenti (DegreeInformations e AdminsList)
let [selectedDegree, setSelectedDegree] = React.useState<string>(''); // PK del Degree
let [searchData, setSearchData] = React.useState<ISuggestionItem[]>([]); // Array di ISuggestionItem (contenente anche Degree per ogni elemento)
let [courses, setCourses] = React.useState<CourseDegree[]>([]); // Corsi di insegnamento
let [reactHelmetContent, setReactHelmetContent] = React.useState<reactHelmetContent>(
{
title: locale?.helmet.courses.title!,
description: locale?.helmet.courses.description!,
href: 'https://studentiunimi.it/courses/',
hrefLang: language!
}
);
const [loadingCourses, setLoadingCourses] = React.useState<boolean>(false);
const [errorLoadingDegrees, setErrorLoadingDegrees] = React.useState<boolean>(false);
const [errorLoadingCourses, setErrorLoadingCourses] = React.useState<boolean>(false);
/* Handlers */
const entitySelectHandler = (item: ISuggestionItem): void => { // Questo viene triggerato quando selezioni qualcosa dal menù
setDegreeTextSearch(item.displayValue);
setSelectedDegree(item.key as unknown as string);
history.push(`/courses/${item.degree?.slug}`);
};
const searchTextHandler = (): void => { // Triggerato quando premi per la ricerca (si è deciso di selezionare il primo risultato)
if (searchData.length === 0) return;
setDegreeTextSearch(searchData[0]?.displayValue);
setSelectedDegree(searchData[0]?.key as unknown as string);
history.push(`/courses/${searchData[0]?.degree?.slug}`);
};
/* Degrees for the SearchBox */
const updateDegreesForSearchBox = React.useCallback(async (searchBoxText: string) => {
setDegreeTextSearch(searchBoxText)
if (searchBoxText === undefined || searchBoxText === "") return;
let degreesResult = await getDegreesForSearchBox(searchBoxText);
if (degreesResult.status !== 200) {
setErrorLoadingDegrees(true);
toggleApiErrorDialog();
console.error("error on degrees result by searchbox text");
return;
}
let tempSearchData : ISuggestionItem[] = [];
(degreesResult.value ?? []).map(x => {
return tempSearchData.push({degree: x, key: x.pk, displayValue: x.name!, searchValue: x.name!});
});
setSearchData(tempSearchData ?? []);
}, [toggleApiErrorDialog]);
/* Courses callBack */
const updateCourses = React.useCallback(async () => {
if (selectedDegree === '' || selectedDegree === undefined) return;
setErrorLoadingCourses(false);
setLoadingCourses(true);
let coursesResult = await getCourses(selectedDegree);
if (coursesResult.status !== 200) {
setLoadingCourses(false);
setErrorLoadingCourses(true);
return;
}
if (loadedDegree !== undefined && loadedDegree?.group?.invite_link !== '' && loadedDegree?.group?.invite_link !== null && loadedDegree?.group?.invite_link !== undefined) {
let mainDegreeGroup: CourseDegree = {
"course": {
pk: undefined,
name: "Gruppo principale",
cfu: 0,
wiki_link: "",
links: [],
group: {
id: loadedDegree?.group?.id!,
title: loadedDegree?.group?.title,
profile_picture: loadedDegree?.group?.profile_picture,
invite_link: loadedDegree?.group?.invite_link
},
},
year: -1,
semester: 0
};
coursesResult.value?.unshift(mainDegreeGroup);
}
setCourses(coursesResult.value ?? []);
setLoadingCourses(false);
setReactHelmetContent({
title: locale?.helmet.degreeLoaded.title1 + `${loadedDegree?.name} (${getDegreeTypeName(loadedDegree?.type!)})` + locale?.helmet.degreeLoaded.title2,
description: locale?.helmet.degreeLoaded.description1 + `${loadedDegree?.name} (${getDegreeTypeName(loadedDegree?.type!)})` + locale?.helmet.degreeLoaded.description2,
href: `https://studentiunimi.it/courses/${loadedDegree?.slug}`,
hrefLang: language!
});
}, [locale, selectedDegree, loadedDegree, language]);
/* This function initializes the VerboseDegree (retrieves degree based on url initialization) */
const initializeDegreeByUrl = React.useCallback(async () => {
if (!didMount.current) {
didMount.current = true;
var states = history.location.pathname.substring(1).split('/').filter(x => x !== '');
var degreeSlug = states.length >= 2 ? states[1].toLowerCase() : '';
if (degreeSlug === '') {
return;
}
let verboseDegreeResult = await getVerboseDegreeBySlug(degreeSlug);
if (verboseDegreeResult.status !== 200) {
return;
}
const verboseDeg = verboseDegreeResult.value ?? undefined;
if (verboseDeg === undefined || verboseDeg === null) return;
setSelectedDegree(verboseDeg.pk! as unknown as string);
setDegreeTextSearch(verboseDeg.name!)
setReactHelmetContent({
title: locale?.helmet.degreeLoaded.title1 + `${verboseDeg?.name} (${getDegreeTypeName(verboseDeg?.type!)})` + locale?.helmet.degreeLoaded.title2,
description: locale?.helmet.degreeLoaded.description1 + `${verboseDeg?.name} (${getDegreeTypeName(verboseDeg?.type!)})` + locale?.helmet.degreeLoaded.description2,
href: `https://studentiunimi.it/courses/${verboseDeg?.slug}`,
hrefLang: language!
});
}
}, [history.location.pathname, locale?.helmet.degreeLoaded.title1, locale?.helmet.degreeLoaded.title2, locale?.helmet.degreeLoaded.description1, locale?.helmet.degreeLoaded.description2, language]);
const updateLoadedDegree = React.useCallback(async () => {
if (selectedDegree === null || selectedDegree === undefined || selectedDegree === "") return;
let degreeResult = await getVerboseDegreeByID(selectedDegree);
if (degreeResult.status !== 200) return;
const degree = degreeResult.value ?? undefined;
if (degree === undefined || degree === null) return;
setLoadedDegree(degree);
}, [selectedDegree]);
React.useEffect(() => {
if (!didMount.current) initializeDegreeByUrl();
}, [searchData, loadedDegree, selectedDegree, initializeDegreeByUrl]);
React.useEffect(() => {
updateCourses();
}, [selectedDegree, loadedDegree, updateCourses]);
React.useEffect(() => {
updateLoadedDegree();
}, [selectedDegree, updateLoadedDegree]);
React.useEffect(() => {
/* Updating content based on browser commands (push and pop) */
return history.listen(async () => {
if (history.action === 'PUSH' || history.action === 'POP') {
var states = history.location.pathname.substring(1).split('/').filter(x => x !== '');
var degreeSlug = states.length >= 2 ? states[1].toLowerCase() : '';
if (degreeSlug === "") {
resetSection();
} else {
didMount.current = false;
initializeDegreeByUrl();
}
}
});
}, [history, initializeDegreeByUrl, updateCourses])
function resetSection() {
setLoadedDegree(null);
setSelectedDegree('');
setDegreeTextSearch('');
};
const modelProps = { isBlocking: false };
const dialogContentProps = {
type: DialogType.largeHeader,
title: locale?.serverError
};
return (
<>
<Helmet>
<meta charSet="utf-8" />
<title>{reactHelmetContent.title}</title>
<meta name="description" content={reactHelmetContent.description} />
<link rel="canonical" href={reactHelmetContent.href} />
<meta name="keywords" content={reactHelmetContent.title + ", " + reactHelmetContent.description + ", Network StudentiUniMi, Studenti UniMi, Network Studenti Unimi, Gruppi telegram unimi, Gruppi unimi, Siti web corsi unimi, Faq corsi unimi, Wiki Unimi"} />
<meta property="og:title" content={reactHelmetContent.title} />
<meta property="og:description" content={reactHelmetContent.description} />
<meta property="og:type" content="website" />
<meta property="og:url" content={reactHelmetContent.href} />
</Helmet>
<div className="groups">
<div className="pt-5">
<Container>
<Row>
<Col lg={3} className="text-center mb-3 mb-lg-0">
<div style={{ marginLeft: 'auto', marginRight: 'auto', maxWidth: 350 }}>
<Image className="mb-2" src={process.env.PUBLIC_URL + '/images/groups/groups.png'} style={{ display: 'inline-block', width: '100%' }} />
</div>
</Col>
<Col lg={9}>
<div className="mb-2">
<div className="mb-1">
<Text variant="medium" styles={semibold} style={{textTransform: 'uppercase', color: theme.palette.themePrimary}}>{locale?.groups.groupsSection.text1}</Text>
</div>
<div className="mb-2">
<span className="mr-1"><Text variant="xLargePlus">{locale?.groups.groupsSection.text2}</Text></span>
<TooltipHost
content={locale?.groups.resetSection}
calloutProps={calloutProps}
styles={hostStyles}
>
<IconButton iconProps={resetIcon} onClick={resetSection} />
</TooltipHost>
</div>
<div className="mb-2 mb-md-4">
<Text variant="large">{locale?.groups.groupsSection.text3}</Text>
</div>
</div>
<div className="search-box">
<Autocomplete
items={searchData}
searchTitle={locale?.groups.findDegreeByName}
suggestionCallback={(item) => entitySelectHandler(item)}
searchCallback={searchTextHandler}
changeCallback={(text) => updateDegreesForSearchBox(text)}
value={degreeTextSearch}
disabled={errorLoadingDegrees}
/>
</div>
<div className="mt-2" style={{ display: errorLoadingDegrees ? 'block' : 'none' }}>
<Text variant="medium" styles={semibold} style={{ color: theme.palette.red }}>{locale?.errorDataLoading}</Text>
</div>
</Col>
</Row>
</Container>
</div>
<div style={{ display: selectedDegree !== '' ? 'block' : 'none', marginTop: '1.5rem' }}>
<GroupList degree={loadedDegree!} courses={courses} loadingCourses={loadingCourses} errorLoadingCourses={errorLoadingCourses} />
<DegreeInformations degree={loadedDegree!} />
<AdminsList degree={loadedDegree!} />
</div>
<Container className="pb-4">
<Separator className="mb-3 mt-3" />
<div className="mb-4">
<Row>
<Col xl={9} lg={8}>
<div className="mb-3">
<div className="mb-1">
<Text variant="medium" styles={semibold} style={{ textTransform: 'uppercase', color: theme.palette.themePrimary }}>{locale?.groups.extraGroupsSection.text1}</Text>
</div>
<div className="mb-2">
<Text variant="xLargePlus">{locale?.groups.extraGroupsSection.text2}</Text>
</div>
<div>
<Text variant="medium">{locale?.groups.extraGroupsSection.text3}</Text>
</div>
</div>
</Col>
<Col xl={3} lg={4} className="text-center">
<div style={{ marginLeft: 'auto', marginRight: 'auto' }}>
<Image className="mb-2" src={process.env.PUBLIC_URL + '/images/groups/extra_groups.png'} style={{ display: 'inline-block', width: '75%' }} />
</div>
</Col>
</Row>
</div>
<AdditionalGroupsView />
</Container>
{/* APIs Error dialog */}
<Dialog
hidden={hideApiErrorDialog}
onDismiss={toggleApiErrorDialog}
dialogContentProps={dialogContentProps}
modalProps={modelProps}
>
<div className="mb-3">
{locale?.errorDataLoading}
</div>
<div style={{ display: 'flex', justifyContent: 'center', marginBottom: 5 }}>
<Image src={process.env.PUBLIC_URL + '/images/message/error.png'} style={{ width: 200 }} />
</div>
<div>
<JsxParser bindings={{ theme: theme, semibold: semibold }} components={{ Text, Link }} jsx={locale?.additionalInformations} />
</div>
<DialogFooter>
<PrimaryButton onClick={toggleApiErrorDialog} text="Ok" />
</DialogFooter>
</Dialog>
</div>
</>
);
}
Example #19
Source File: OrganizationView.tsx From website with MIT License | 4 votes |
OrganizationView = () => {
var theme = useTheme();
const locale = LocalizationService.strings();
var language: string | undefined = LocalizationService.getLanguage();
const networkMembers = getNetworkMembers();
const icon: IIconProps = { iconName: 'DocumentSearch' };
const imageProperties = { display: 'inline-block', width: '100%' };
return (
<div className="organization pb-3">
<div className="pt-5 pb-5" style={{ backgroundColor: theme.palette.themeDarkAlt }}>
<Container>
<Row>
<Col lg={4} className="text-center">
<div style={{ marginLeft: 'auto', marginRight: 'auto', maxWidth: 300 }}>
<Image id="logo" className="mb-2" src={process.env.PUBLIC_URL + '/images/organization.png'} style={imageProperties} />
</div>
</Col>
<Col lg={8} className="mb-2">
<div className="mb-2">
<Text variant="xLargePlus" style={{ color: theme.palette.white }}>{locale?.aboutUs.text1}</Text>
</div>
<div className="mb-2">
<Text variant="large" style={{ color: theme.palette.white }}>{locale?.aboutUs.text2}</Text>
</div>
<div className="mb-3">
<Text variant="medium" style={{ color: theme.palette.white }}>{locale?.aboutUs.text3}</Text>
</div>
<div className="mb-2">
<CompoundButton primary theme={theme} secondaryText={locale?.aboutUs.button.text2} href="https://github.com/StudentiUniMi/docs/raw/main/statuto.pdf" style={{ textDecoration: 'none', boxShadow: theme.effects.elevation8 }} iconProps={icon}>
{locale?.aboutUs.button.text1}
</CompoundButton>
</div>
</Col>
</Row>
</Container>
</div>
<div className="pt-4 pb-4">
<div className="mb-4 text-center"><Text variant="xLarge" styles={semibold} style={{ color: theme.palette.themePrimary }}>{locale?.aboutUs.header1}</Text></div>
<div style={{maxWidth: 230, marginLeft: 'auto', marginRight: 'auto'}}>
<Persona
size={PersonaSize.size72}
imageUrl={"https://studentiunimi-groups-propics.marcoaceti.workers.dev/26170256.png"}
text={networkMembers[0].name}
onRenderPrimaryText={() => <Text variant="medium" styles={semibold}>{networkMembers[0].name}</Text>}
secondaryText={networkMembers[0].username}
onRenderSecondaryText={() => <Text variant="medium"><Link href={`https://t.me/${networkMembers[0].username}`}>@{networkMembers[0].username}</Link></Text>}
/>
</div>
</div>
<div className="pb-4">
<Container>
<div className="mb-4 text-center"><Text variant="xLarge" styles={semibold} style={{color: theme.palette.themePrimary}}>{locale?.aboutUs.header2}</Text></div>
<Row className="justify-content-center">
{
(networkMembers.slice(1, networkMembers.length)).map((x, i) =>
<>
<Col className="mb-4" lg={3} md={6} sm={6} xs={12}>
<div style={{ maxWidth: 240, marginLeft: 'auto', marginRight: 'auto' }}>
<Persona
size={PersonaSize.size72}
imageUrl={`https://studentiunimi-groups-propics.marcoaceti.workers.dev/${x.user_id}.png`}
text={x.name}
onRenderPrimaryText={() => <Text variant="medium" styles={semibold}>{x.name}</Text>}
secondaryText={x.username}
onRenderSecondaryText={() => <Text variant="medium"><Link href={`https://t.me/${x.username}`}>@{x.username}</Link></Text>}
/>
</div>
</Col>
</>
)
}
</Row>
</Container>
</div>
<div className="pb-4">
<Container>
<div className="mb-4 text-center"><Text variant="xLarge" styles={semibold} style={{ color: theme.palette.themePrimary }}>{locale?.contributors.header1}</Text></div>
<Row className="justify-content-center">
{
developers.map((x:any, i:any) =>
<>
<Col className="mb-3" lg={4} sm={6} xs={12}>
<div style={{ maxWidth: 250, marginLeft: 'auto', marginRight: 'auto' }}>
<Persona
size={PersonaSize.size72}
imageUrl={`https://studentiunimi-groups-propics.marcoaceti.workers.dev/${x.user_id}.png`}
text={x.name}
onRenderPrimaryText={() => <Text variant="medium" styles={semibold}><Link href={x.github}>{x.name}</Link></Text>}
secondaryText={x.username}
onRenderSecondaryText={() => <Text variant="medium"><Link href={`https://t.me/${x.username}`}>@{x.username}</Link></Text>}
tertiaryText={x.description[language!]}
onRenderTertiaryText={() => <Text variant="small">{x.description[language!]}</Text>}
/>
</div>
</Col>
</>
)
}
</Row>
</Container>
</div>
</div>
)
}
Example #20
Source File: RulesView.tsx From website with MIT License | 4 votes |
Rules = () => {
const theme = useTheme();
const locale = LocalizationService.strings();
var language: string | undefined = LocalizationService.getLanguage();
const icon: IIconProps = { iconName: 'QandA' };
const rulesData: Rule[] = getRules();
const imageProperties = { display: 'inline-block', width: '100%' };
const [isCalloutVisible, { toggle: toggleIsCalloutVisible }] = useBoolean(false);
const buttonId = useId('callout-button');
const styles = mergeStyleSets({
callout: {
maxWidth: 800,
padding: '20px 24px',
marginLeft: '5px',
marginRight: '15px'
},
button: {
width: 'auto',
height: 'auto',
borderRadius: 3
},
});
return (
<div className="rules pb-3">
<div className="pt-5 pb-5 mb-4" style={{ backgroundColor: theme.palette.themePrimary }}>
<Container>
<Row>
<Col lg={4} className="text-center">
<div style={{ marginLeft: 'auto', marginRight: 'auto', maxWidth: 300 }}>
<Image id="logo" className="mb-2" src={process.env.PUBLIC_URL + '/images/rules.png'} style={imageProperties} />
</div>
</Col>
<Col lg={8}>
<div className="mb-2">
<Text variant="xLargePlus" style={{color: theme.palette.white}}>{locale?.rules.text1}</Text>
</div>
<div className="mb-3">
<Text variant="large" style={{ color: theme.palette.white }}>{locale?.rules.text2}</Text>
</div>
<div className="mb-3">
<DefaultButton
id={buttonId}
onClick={toggleIsCalloutVisible}
text={locale?.rules.question}
className={styles.button}
iconProps={icon}
theme={theme}
style={{ boxShadow: theme.effects.elevation8 }}
/>
{isCalloutVisible && (
<Callout
className={styles.callout}
role="alertdialog"
gapSpace={3}
target={`#${buttonId}`}
onDismiss={toggleIsCalloutVisible}
directionalHint={DirectionalHint.bottomCenter}
setInitialFocus
>
<Text block variant="medium" className="mb-1" styles={semibold}>{locale?.rules.answer.text1}</Text>
<Text block variant="small"><JsxParser bindings={{ theme: theme }} components={{ Text, Link }} jsx={locale?.rules.answer.text2} /></Text>
</Callout>
)}
</div>
<div>
<Text variant="medium" style={{ color: theme.palette.white }}><i>{locale?.rules.text3}</i></Text>
</div>
</Col>
</Row>
</Container>
</div>
<div className="mb-4">
<div className="mb-4 text-center">
<Text variant="xLarge">{locale?.rules.header}</Text>
</div>
</div>
<div className="mb-3">
<Container>
{
rulesData.map((x, i) => {
return (
<Accordion style={{ backgroundColor: theme.palette.white, color: theme.palette.black, boxShadow: theme.effects.elevation8, marginRight: 10, marginLeft: 10 }} key={i}>
<AccordionSummary
expandIcon={<ExpandMoreIcon style={{ color: theme.palette.black }} />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Text variant="medium" style={{ color: theme.palette.themePrimary }} styles={semibold}>{x.title![language!]}</Text>
</AccordionSummary>
<AccordionDetails>
<Text variant="medium">
<JsxParser bindings={{ theme: theme, semibold: semibold }} components={{ Text, Link }} jsx={x.description![language!]} />
</Text>
</AccordionDetails>
</Accordion>
)
})
}
</Container>
</div>
</div>
)
}
Example #21
Source File: UniversityView.tsx From website with MIT License | 4 votes |
UniversityView = () => {
var theme = useTheme();
let didMount = React.useRef(false);
const locale = LocalizationService.strings();
var language: string | undefined = LocalizationService.getLanguage();
const history = useHistory();
//const whiteText = '#faf9f8';
const imageProperties = { display: 'inline-block', width: '80%' };
const universityLinks: any[] = getUniversityLinks();
/* ChoiceGroup for university links */
const iconProps: any = { fontSize: '24px' };
const options: IChoiceGroupOption[] = [];
const itemSize = 100;
const choiceGroupOptionsStyle: IChoiceGroupOptionStyles = {
choiceFieldWrapper: {
width: itemSize + "px",
height: itemSize + "px"
},
labelWrapper: {
maxWidth: itemSize / (3 / 4) + "px",
height: "auto",
},
field: {
height: "100%",
padding: "0px"
}
};
/* Workaround to not show selected choicegroup */
const [selectedChoiceGroup, setSelectedChoiceGroup] = React.useState<string>("");
const selectionChanged = (ev?: React.FormEvent<HTMLElement | HTMLInputElement>, option?: IChoiceGroupOption): void => { setSelectedChoiceGroup(""); }
universityLinks.map((x) => {
if (x.icon !== "" && x.link !== "") options.push({
key: x.name![language!],
text: x.name![language!],
styles: choiceGroupOptionsStyle,
iconProps: { iconName: x.icon!, className: iconProps, color: theme.palette.themePrimary },
onClick: () => {redirectToLink(x.link!)}
});
return options;
});
/* Remove title properties from documentCardTitles */
React.useEffect(() => {
const divList = document.getElementsByClassName("ms-DocumentCardTitle");
for (let i: number = 0; i < divList.length; i++) {
divList[i].removeAttribute('title');
}
});
const [departments, setDepartments] = React.useState<Department[]>([]);
const [representatives, setRepresentatives] = React.useState<Representative[]>([]);
const [selectedDepartment, setSelectedDepartment] = React.useState<string>('');
const [loadingRepresentatives, setLoadingRepresentatives] = React.useState<boolean>(false);
const [errorLoadingRepresentatives, setErrorLoadingRepresentatives] = React.useState<boolean>(false);
const [errorLoadingDepartments, setErrorLoadingDepartments] = React.useState<boolean>(false);
const departmentSelectionChanged = (ev?: React.FormEvent<HTMLElement | HTMLInputElement>, option?: IDropdownOption): void => {
setSelectedDepartment(option?.key as string ?? '');
history.push(`/representatives/${option?.data.slug as string}`);
};
/* Departments callBack */
const updateDepartments = React.useCallback(async () => {
setErrorLoadingDepartments(false);
let departmentsResult = await getDepartments();
if (departmentsResult.status !== 200) {
setErrorLoadingDepartments(true);
return;
}
//console.log("Departments result: ", departmentsResult.value ?? []);
setDepartments(departmentsResult.value ?? []);
}, []);
/* Representatives callBack */
const updateRepresentatives = React.useCallback(async () => {
if (selectedDepartment === '' || selectedDepartment === undefined) return;
setLoadingRepresentatives(true);
setErrorLoadingRepresentatives(false);
let representativesResult = await getRepresentatives(selectedDepartment);
if (representativesResult.status !== 200) {
setLoadingRepresentatives(false);
setErrorLoadingRepresentatives(true);
}
//console.log("Representatives result: ", representativesResult.value ?? []);
setLoadingRepresentatives(false);
setRepresentatives(representativesResult.value ?? []);
}, [setRepresentatives, selectedDepartment]);
/* This function initializes representatives based on url parameters */
const initializeRepresentativesViaUrl = React.useCallback(() => {
if (!didMount.current && departments.length !== 0) {
didMount.current = true
var states = history.location.pathname.substring(1).split('/').filter(x => x !== '');
var departmentSlug = states.length >= 2 ? states[1] : '';
//console.log("Department slug: ", departmentSlug)
setSelectedDepartment(departments.filter(x => x.slug === departmentSlug)[0]?.pk as unknown as string);
}
}, [departments, history.location.pathname]);
React.useEffect(() => {
if (!didMount.current) {
updateDepartments();
}
}, [updateDepartments]);
React.useEffect(() => {
updateRepresentatives();
}, [selectedDepartment, updateRepresentatives]);
React.useEffect(() => {
if (!didMount.current) initializeRepresentativesViaUrl();
}, [initializeRepresentativesViaUrl, departments]);
let departmentOptions: IDropdownOption[] = [];
departments.forEach(x => {
if (x.representative_count !== 0) departmentOptions.push({ key: x.pk, text: x.name ?? "", data: { icon: x.icon, slug: x.slug }, disabled: x.representative_count === 0 });
});
return (
<div className="university">
<div className="pt-5 pb-5 mb-4" style={{ backgroundColor: theme.palette.themeDark }}>
<Container>
<Row>
<Col xl={9} lg={8} className="mb-3 mb-lg-0">
<div className="mb-2">
<Text variant="xLargePlus" style={{ color: theme.palette.white }}>{locale?.university.header.text1}</Text>
</div>
<div className="mb-3">
<Text variant="large" style={{ color: theme.palette.white }}>{locale?.university.header.text2}</Text>
</div>
</Col>
<Col xl={3} lg={4} className="text-center">
<div style={{ marginLeft: 'auto', marginRight: 'auto', maxWidth: 500 }}>
<Image id="logo" className="mb-2" src={process.env.PUBLIC_URL + '/images/university.png'} style={{ display: 'inline-block', width: '80%' }} />
</div>
</Col>
</Row>
</Container>
</div>
<div>
<Container>
<div className="mb-3 text-center">
<Text variant="xLarge"><Icon iconName="NewsSearch" /> {locale?.university.news.title}</Text>
</div>
<div className="mb-3">
<Slider />
</div>
</Container>
</div>
<div className="pt-5 pb-5" style={{ backgroundColor: theme.palette.themeTertiary }}>
<Container>
<Row>
<Col lg={4} className="text-center">
<div style={{ marginLeft: 'auto', marginRight: 'auto', maxWidth: 300 }}>
<Image id="logo" className="mb-2" src={process.env.PUBLIC_URL + '/images/university_links.png'} style={imageProperties} />
</div>
</Col>
<Col lg={8} className="mb-2">
<div className="mb-2">
<Text variant="xLargePlus" style={{color: theme.palette.white}}>{locale?.university.linksAndRedirects.text1}</Text>
</div>
<div className="mb-3">
<Text variant="large" style={{ color: theme.palette.white }}>{locale?.university.linksAndRedirects.text2}</Text>
</div>
<div className="text-center justify-content-center university-links" style={{ marginLeft: 'auto', marginRight: 'auto' }}>
<ChoiceGroup options={options} onChange={selectionChanged} selectedKey={selectedChoiceGroup} />
</div>
</Col>
</Row>
</Container>
</div>
<div className="pt-5 pb-5 mb-4" style={{ backgroundColor: theme.palette.themeDarkAlt }}>
<Container>
<Row>
<Col>
<div className="mb-2">
<div className="mb-2">
<Text variant="xLarge" style={{ color: theme.palette.white }}>
{locale?.university.text1}
</Text>
</div>
<div className="mb-2">
<Text variant="large" style={{ color: theme.palette.white }}>
{locale?.university.text2}
</Text>
</div>
<div className="mb-2 text-center" style={{ maxWidth: '400px', marginRight: 'auto'}}>
<Dropdown
placeholder={locale?.university.departmentSelect}
label={locale?.university.departmentSelect}
onRenderLabel={() => <Text style={{ color: theme.palette.white }} styles={semibold}>{locale?.university.departmentSelect}</Text>}
options={departmentOptions}
onChange={departmentSelectionChanged}
selectedKey={selectedDepartment}
onRenderTitle={onRenderTitle}
onRenderOption={onRenderOption}
errorMessage={errorLoadingDepartments ? locale?.errorLoadingDepartments : undefined}
disabled={errorLoadingDepartments || departments.length === 0}
/>
</div>
</div>
</Col>
<Col lg={3} className="text-center">
<div style={{ marginLeft: 'auto', marginRight: 'auto', maxWidth: 300 }}>
<Image id="logo" className="mb-2" src={process.env.PUBLIC_URL + '/images/representatives.png'} style={{ display: 'inline-block', width: '100%' }} />
</div>
</Col>
</Row>
</Container>
</div>
<div style={{ display: selectedDepartment !== '' && selectedDepartment !== undefined ? 'block' : 'none' }}>
<Container>
<RepresentativesList data={representatives} loadingRepresentatives={loadingRepresentatives} errorLoadingRepresentatives={errorLoadingRepresentatives} />
</Container>
</div>
</div>
)
}
Example #22
Source File: Options.tsx From hypertrons-crx with Apache License 2.0 | 4 votes |
Options: React.FC = () => {
const [settings, setSettings] = useState(new Settings());
const [metaData, setMetaData] = useState(new MetaData());
const [inited, setInited] = useState(false);
const [version, setVersion] = useState('0.0.0');
const [checkingUpdate, setCheckingUpdate] = useState(false);
const [token, setToken] = useState('');
const [checkingToken, setCheckingToken] = useState(false);
const [showDialogToken, setShowDialogToken] = useState(false);
const [showDialogTokenError, setShowDialogTokenError] = useState(false);
const [showDialogNotification, setShowDialogNotification] = useState(false);
const [notificationId, setNotificationId] = useState(0);
const [notification, setNotification] = useState('');
const [updateStatus, setUpdateStatus] = useState(UpdateStatus.undefine);
const [updateUrl, setUpdateUrl] = useState(
'https://github.com/hypertrons/hypertrons-crx/releases'
);
const tokenCurrent = metaData.token;
const graphOptions: IChoiceGroupOption[] = [
{
key: 'antv',
text: 'Antv',
},
{
key: 'echarts',
text: 'Echarts',
},
];
const locale = settings.locale;
const localeOptions: IChoiceGroupOption[] = [
{
key: 'en',
text: 'English',
},
{
key: 'zh_CN',
text: '简体中文 (Simplified Chinese)',
},
];
useEffect(() => {
const initMetaData = async () => {
const tempMetaData = await loadMetaData();
setMetaData(tempMetaData);
if (tempMetaData.token !== '') {
setToken(tempMetaData.token);
}
const notificationInformation = await getNotificationInformation();
if (
notificationInformation.is_published &&
tempMetaData.idLastNotication < notificationInformation.id
) {
if (locale === 'zh_CN') {
setNotification(notificationInformation.content.zh);
} else {
setNotification(notificationInformation.content.en);
}
setNotificationId(notificationInformation.id);
setShowDialogNotification(true);
}
};
if (!inited) {
initMetaData();
}
}, [inited, locale, metaData]);
useEffect(() => {
const initSettings = async () => {
const temp = await loadSettings();
setSettings(temp);
setInited(true);
};
if (!inited) {
initSettings();
}
}, [inited, settings]);
const getVersion = async () => {
let version = (await chrome.management.getSelf()).version;
setVersion(version);
};
useEffect(() => {
getVersion();
}, [version]);
const saveSettings = async (settings: Settings) => {
setSettings(settings);
await chromeSet('settings', settings.toJson());
};
const checkUpdateManually = async () => {
setUpdateStatus(UpdateStatus.undefine);
setCheckingUpdate(true);
const [currentVersion, latestVersion, updateUrl] = await checkUpdate();
if (compareVersion(currentVersion, latestVersion) === -1) {
setUpdateUrl(updateUrl);
setUpdateStatus(UpdateStatus.yes);
} else {
setUpdateStatus(UpdateStatus.no);
}
setCheckingUpdate(false);
};
if (!inited) {
return <div />;
}
return (
<Stack>
{showDialogNotification && (
<Dialog
hidden={!showDialogNotification}
onDismiss={() => {
setShowDialogNotification(false);
}}
dialogContentProps={{
type: DialogType.normal,
title: getMessageByLocale(
'global_notificationTitle',
settings.locale
),
}}
modalProps={{
isBlocking: true,
}}
>
<Text variant="mediumPlus">{notification}</Text>
<DialogFooter>
<DefaultButton
onClick={() => {
setShowDialogNotification(false);
}}
>
{getMessageByLocale('global_btn_ok', settings.locale)}
</DefaultButton>
<PrimaryButton
onClick={async () => {
metaData.idLastNotication = notificationId;
setMetaData(metaData);
await chromeSet('meta_data', metaData.toJson());
setShowDialogNotification(false);
}}
>
{getMessageByLocale('global_btn_disable', settings.locale)}
</PrimaryButton>
</DialogFooter>
</Dialog>
)}
{showDialogToken && (
<Dialog
hidden={!showDialogToken}
onDismiss={() => {
setShowDialogToken(false);
}}
dialogContentProps={{
type: DialogType.normal,
title: getMessageByLocale(
'options_token_dialog_title',
settings.locale
),
}}
modalProps={{
isBlocking: true,
}}
>
<p style={{ fontSize: 14, color: '#6a737d', margin: 5 }}>
{getMessageByLocale(
'options_token_dialog_description',
settings.locale
)}
</p>
<Stack horizontal style={{ fontSize: 16, margin: 5 }}>
<Link
href="https://github.com/settings/tokens/new"
target="_blank"
underline
>
{getMessageByLocale(
'options_token_dialog_message',
settings.locale
)}
</Link>
</Stack>
{checkingToken && (
<Spinner
label={getMessageByLocale(
'options_token_dialog_checking',
settings.locale
)}
/>
)}
{showDialogTokenError && (
<MessageBar messageBarType={MessageBarType.error}>
{getMessageByLocale(
'options_token_dialog_error',
settings.locale
)}
</MessageBar>
)}
<Stack
horizontal
horizontalAlign="space-around"
verticalAlign="end"
style={{ margin: '10px' }}
tokens={{
childrenGap: 15,
}}
>
<TextField
style={{ width: '200px' }}
defaultValue={token}
onChange={(e, value) => {
if (value) {
setShowDialogTokenError(false);
setToken(value);
}
}}
/>
<PrimaryButton
disabled={checkingToken}
onClick={async () => {
setCheckingToken(true);
const result = await checkIsTokenAvailabe(token);
setCheckingToken(false);
if ('id' in result) {
metaData.token = token;
metaData.avatar = result['avatar_url'];
metaData.name = result['name'];
metaData.id = result['id'];
setMetaData(metaData);
await chromeSet('meta_data', metaData.toJson());
setShowDialogToken(false);
} else {
setShowDialogTokenError(true);
}
}}
>
{getMessageByLocale('global_btn_ok', settings.locale)}
</PrimaryButton>
</Stack>
{tokenCurrent !== '' && (
<DefaultButton
onClick={async () => {
metaData.token = '';
metaData.avatar = '';
metaData.name = '';
metaData.id = '';
setMetaData(metaData);
await chromeSet('meta_data', metaData.toJson());
setShowDialogToken(false);
}}
style={{
width: 120,
}}
>
{getMessageByLocale('options_token_btn_rmToken', settings.locale)}
</DefaultButton>
)}
</Dialog>
)}
<Stack horizontalAlign="center" style={{ paddingBottom: '10px' }}>
<h1>PERCEPTOR</h1>
<sub>{`version ${version}`}</sub>
</Stack>
<Stack
horizontalAlign="center"
tokens={{
childrenGap: 30,
}}
>
<Stack.Item className="Box">
<TooltipHost
content={getMessageByLocale(
'options_enable_toolTip',
settings.locale
)}
>
<Stack.Item className="Box-header">
<h2 className="Box-title">
{getMessageByLocale('options_enable_title', settings.locale)}
</h2>
</Stack.Item>
</TooltipHost>
<Stack
style={{ margin: '10px 25px' }}
tokens={{
childrenGap: 10,
}}
>
<p>
{getMessageByLocale('options_enable_toolTip', settings.locale)}.
</p>
<Toggle
label={getMessageByLocale(
'options_enable_toggle_autoCheck',
settings.locale
)}
defaultChecked={settings.isEnabled}
onText={getMessageByLocale(
'global_toggle_onText',
settings.locale
)}
offText={getMessageByLocale(
'global_toggle_offText',
settings.locale
)}
onChange={async (e, checked) => {
settings.isEnabled = checked;
await saveSettings(settings);
}}
/>
</Stack>
</Stack.Item>
<Stack.Item className="Box">
<TooltipHost
content={getMessageByLocale(
'options_locale_toolTip',
settings.locale
)}
>
<Stack.Item className="Box-header">
<h2 className="Box-title">
{getMessageByLocale('options_locale_title', settings.locale)}
</h2>
</Stack.Item>
</TooltipHost>
<Stack style={{ margin: '10px 25px' }}>
<p>
{getMessageByLocale('options_locale_toolTip', settings.locale)} :
</p>
<ChoiceGroup
defaultSelectedKey={settings.locale}
options={localeOptions}
onChange={async (e, option: any) => {
settings.locale = option.key;
await saveSettings(settings);
}}
/>
</Stack>
</Stack.Item>
<Stack.Item className="Box">
<TooltipHost
content={getMessageByLocale(
'options_components_toolTip',
settings.locale
)}
>
<Stack.Item className="Box-header">
<h2 className="Box-title">
{getMessageByLocale(
'options_components_title',
settings.locale
)}
</h2>
</Stack.Item>
</TooltipHost>
<Stack
style={{ margin: '10px 25px' }}
tokens={{
childrenGap: 10,
}}
>
<p>
{getMessageByLocale(
'options_components_toolTip',
settings.locale
)}{' '}
:
</p>
<Checkbox
label={getMessageByLocale(
'component_developerCollabrationNetwork_title',
settings.locale
)}
defaultChecked={settings.developerNetwork}
onChange={async (e, checked) => {
settings.developerNetwork = checked;
await saveSettings(settings);
}}
/>
<Checkbox
label={getMessageByLocale(
'component_projectCorrelationNetwork_title',
settings.locale
)}
defaultChecked={settings.projectNetwork}
onChange={async (e, checked) => {
settings.projectNetwork = checked;
await saveSettings(settings);
}}
/>
</Stack>
</Stack.Item>
<Stack.Item className="Box">
<TooltipHost
content={getMessageByLocale(
'options_graphType_toolTip',
settings.locale
)}
>
<Stack.Item className="Box-header">
<h2 className="Box-title">
{getMessageByLocale('options_graphType_title', settings.locale)}
</h2>
</Stack.Item>
</TooltipHost>
<Stack style={{ margin: '10px 25px' }}>
<p>
{getMessageByLocale('options_graphType_toolTip', settings.locale)}{' '}
:
</p>
<ChoiceGroup
defaultSelectedKey={settings.graphType}
options={graphOptions}
onChange={async (e, option: any) => {
settings.graphType = option.key as GraphType;
await saveSettings(settings);
}}
/>
</Stack>
</Stack.Item>
<Stack.Item className="Box">
<TooltipHost
content={getMessageByLocale(
'options_update_toolTip',
settings.locale
)}
>
<Stack.Item className="Box-header">
<h2 className="Box-title">
{getMessageByLocale('options_update_title', settings.locale)}
</h2>
</Stack.Item>
</TooltipHost>
<Stack
style={{ margin: '10px 25px' }}
tokens={{
childrenGap: 10,
}}
>
<p>
{getMessageByLocale('options_update_toolTip', settings.locale)}.
</p>
<Toggle
label={getMessageByLocale(
'options_update_toggle_autoCheck',
settings.locale
)}
defaultChecked={settings.checkForUpdates}
onText={getMessageByLocale(
'global_toggle_onText',
settings.locale
)}
offText={getMessageByLocale(
'global_toggle_offText',
settings.locale
)}
onChange={async (e, checked) => {
settings.checkForUpdates = checked;
await saveSettings(settings);
}}
/>
{checkingUpdate && (
<Stack horizontalAlign="start">
<Spinner
label={getMessageByLocale(
'options_update_checking',
settings.locale
)}
/>
</Stack>
)}
{updateStatus === UpdateStatus.yes && (
<MessageBar
messageBarType={MessageBarType.success}
isMultiline={false}
>
{getMessageByLocale(
'options_update_btn_updateStatusYes',
settings.locale
)}
<Link href={updateUrl} target="_blank" underline>
{getMessageByLocale(
'options_update_btn_getUpdate',
settings.locale
)}
</Link>
</MessageBar>
)}
{updateStatus === UpdateStatus.no && (
<MessageBar
messageBarType={MessageBarType.info}
isMultiline={false}
>
{getMessageByLocale(
'options_update_btn_updateStatusNo',
settings.locale
)}
</MessageBar>
)}
<DefaultButton
style={{
width: 120,
}}
disabled={checkingUpdate}
onClick={async () => {
await checkUpdateManually();
}}
>
{getMessageByLocale(
'options_update_btn_checkUpdate',
settings.locale
)}
</DefaultButton>
</Stack>
</Stack.Item>
<Stack.Item className="Box">
<TooltipHost
content={getMessageByLocale(
'options_token_toolTip',
settings.locale
)}
>
<Stack.Item className="Box-header">
<h2 className="Box-title">
{getMessageByLocale('options_token_title', settings.locale)}
</h2>
</Stack.Item>
</TooltipHost>
<Stack
style={{ margin: '10px 25px' }}
tokens={{
childrenGap: 10,
}}
>
<p>
{getMessageByLocale('options_token_toolTip', settings.locale)} :
</p>
{tokenCurrent !== '' && (
<Stack
horizontal
verticalAlign="center"
style={{
margin: '5px',
padding: '3px',
width: '300px',
boxShadow: '4px 4px 10px rgba(0, 0, 0, 0.2)',
}}
tokens={{
childrenGap: 5,
}}
>
<Image
width={75}
height={75}
src={metaData.avatar}
imageFit={ImageFit.centerCover}
/>
<Text
variant="large"
style={{
marginLeft: 25,
maxWidth: 200,
wordWrap: 'break-word',
}}
>
{metaData.name}
</Text>
</Stack>
)}
<DefaultButton
onClick={() => {
setShowDialogToken(true);
}}
style={{
width: 120,
}}
>
{getMessageByLocale(
'options_token_btn_setToken',
settings.locale
)}
</DefaultButton>
</Stack>
</Stack.Item>
<Stack.Item className="Box">
<TooltipHost
content={getMessageByLocale(
'options_about_toolTip',
settings.locale
)}
>
<Stack.Item className="Box-header">
<h2 className="Box-title">
{getMessageByLocale('options_about_title', settings.locale)}
</h2>
</Stack.Item>
</TooltipHost>
<Stack style={{ margin: '10px 25px' }}>
<p>
{getMessageByLocale('options_about_description', settings.locale)}
</p>
<p>
{getMessageByLocale(
'options_about_description_website',
settings.locale
)}
</p>
<Link href={HYPERTRONS_CRX_WEBSITE} target="_blank" underline>
{HYPERTRONS_CRX_WEBSITE}
</Link>
</Stack>
</Stack.Item>
</Stack>
</Stack>
);
}
Example #23
Source File: Popup.tsx From hypertrons-crx with Apache License 2.0 | 4 votes |
Popup: React.FC = () => {
const [settings, setSettings] = useState(new Settings());
const [metaData, setMetaData] = useState(new MetaData());
const [inited, setInited] = useState(false);
useEffect(() => {
const initSettings = async () => {
const temp = await loadSettings();
setSettings(temp);
setInited(true);
};
if (!inited) {
initSettings();
}
}, [inited, settings]);
useEffect(() => {
const initMetaData = async () => {
const temp = await loadMetaData();
setMetaData(temp);
};
initMetaData();
}, []);
const saveSettings = async (settings: Settings) => {
setSettings(settings);
await chromeSet('settings', settings.toJson());
};
if (!inited) {
return <div />;
}
return (
<Stack horizontalAlign="center">
<Stack
horizontalAlign="space-around"
verticalAlign="center"
style={{ margin: '5px', padding: '3px' }}
tokens={{
childrenGap: 10,
}}
>
<Stack horizontalAlign="center">
<Toggle
label={getMessageByLocale(
'options_enable_toggle_autoCheck',
settings.locale
)}
defaultChecked={settings.isEnabled}
onText={getMessageByLocale('global_toggle_onText', settings.locale)}
offText={getMessageByLocale(
'global_toggle_offText',
settings.locale
)}
onChange={async (e, checked) => {
settings.isEnabled = checked;
await saveSettings(settings);
}}
/>
</Stack>
{metaData.token !== '' && (
<Stack
horizontal
verticalAlign="center"
style={{
margin: '5px',
padding: '3px',
width: '200px',
}}
tokens={{
childrenGap: 5,
}}
>
<Image
width={75}
height={75}
src={metaData.avatar}
imageFit={ImageFit.centerCover}
/>
<Text
variant="large"
style={{ marginLeft: 25, width: 100, wordWrap: 'break-word' }}
>
{metaData.name}
</Text>
</Stack>
)}
{metaData.token === '' && (
<DefaultButton
onClick={() => {
chrome.runtime.openOptionsPage();
}}
style={{
width: 120,
}}
>
{getMessageByLocale('options_token_title', settings.locale)}
</DefaultButton>
)}
</Stack>
</Stack>
);
}
Example #24
Source File: MeetingPage.tsx From msteams-meetings-template with MIT License | 4 votes |
function MeetingPageComponent(props: MeetingPageProps) {
const [validationEnabled, setValidationEnabled] = useState(false);
function onSubjectChanged(
evt: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>,
newValue: string | undefined
) {
// The meeting objects are small, cloning is cheap enough
// Normally would use immutable records or similar to avoid overhead.
const nextMeeting = _.cloneDeep(props.meeting);
nextMeeting.subject = newValue ?? '';
props.setMeeting(nextMeeting);
}
function onStartDateSelected(date?: Moment) {
const nextMeeting = _.cloneDeep(props.meeting);
nextMeeting.startDateTime = date ?? nextMeeting.startDateTime;
// If start >= end, adjust to be the same delta as before from the start time
if (nextMeeting.startDateTime.isSameOrAfter(nextMeeting.endDateTime)) {
const existingDelta = moment(props.meeting.endDateTime).diff(
moment(props.meeting.startDateTime)
);
const newEndDateTime = moment(nextMeeting.startDateTime).add(
existingDelta
);
if (nextMeeting.startDateTime.isSameOrAfter(newEndDateTime)) {
newEndDateTime.add(existingDelta);
}
nextMeeting.endDateTime = newEndDateTime;
}
props.setMeeting(nextMeeting);
}
function onEndDateSelected(date?: Moment) {
const nextMeeting = _.cloneDeep(props.meeting);
const newEndDateTime = date ?? nextMeeting.endDateTime;
// Allow the change only if it maintains start < end
if (!nextMeeting.startDateTime.isAfter(newEndDateTime)) {
nextMeeting.endDateTime = newEndDateTime;
}
props.setMeeting(nextMeeting);
}
function onCreate() {
if (!!props.validationFailures.invalidTitle) {
setValidationEnabled(true);
return;
}
props.createMeeting(props.meeting);
}
if (props.creationInProgress) {
return (
<div className="spinnerContainer">
<Spinner size={SpinnerSize.large} />
</div>
);
}
return (
<div className="newMeetingContainer">
<Stack
className="container"
verticalFill
tokens={{
childrenGap: 35
}}
>
<Stack horizontal tokens={{ childrenGap: 15 }}>
<StackItem grow>
<FontIcon iconName="Calendar" className={meetingIconClass} />
<Text variant="xLarge" styles={boldStyle}>
<FormattedMessage id="meetingPage.header" />
</Text>
</StackItem>
<StackItem align="end" className="newMeetingButtons">
<Stack horizontal tokens={{ childrenGap: 10 }}>
<PrimaryButton
className="teamsButton"
disabled={props.creationInProgress}
onClick={() => onCreate()}
ariaLabel={translate('meetingPage.create.ariaLabel')}
>
<FormattedMessage id="meetingPage.create" />
</PrimaryButton>
<DefaultButton
className="teamsButtonInverted"
disabled={props.creationInProgress}
onClick={() => props.cancel()}
ariaLabel={translate('meetingPage.cancel.ariaLabel')}
>
<FormattedMessage id="meetingPage.cancel" />
</DefaultButton>
</Stack>
</StackItem>
</Stack>
<Stack horizontal>
<StackItem className="newMeetingInputIcon">
<FontIcon iconName="Edit" className={inputIconClass} />
</StackItem>
<StackItem grow>
<TextField
className="newMeetingInput"
placeholder={translate('meetingPage.title.input')}
value={props.meeting?.subject}
underlined
onChange={onSubjectChanged}
errorMessage={
validationEnabled
? props.validationFailures.invalidTitle
: undefined
}
/>
</StackItem>
</Stack>
<div className="newMeetingDatePickerContainer">
<FontIcon iconName="Clock" className={inputIconClass} />
<div className="newMeetingPicker">
<DateTimePicker
dateTime={props.meeting.startDateTime}
minDate={moment()}
onTimeUpdated={onStartDateSelected}
includeDuration={false}
iconName="ReplyAlt"
/>
<DateTimePicker
dateTime={props.meeting.endDateTime}
minDate={props.meeting.startDateTime}
onTimeUpdated={onEndDateSelected}
includeDuration={true}
/>
</div>
</div>
{/* MOBILE BUTTON GROUP */}
</Stack>
<StackItem className="newMeetingButtonsMobile">
<Stack horizontal tokens={{ childrenGap: 10 }}>
<PrimaryButton
className="teamsButton teamsButtonFullWidth"
disabled={props.creationInProgress}
onClick={() => onCreate()}
ariaLabel={translate('meetingPage.create.ariaLabel')}
>
<FormattedMessage id="meetingPage.create" />
</PrimaryButton>
<DefaultButton
className="teamsButtonInverted teamsButtonFullWidth"
disabled={props.creationInProgress}
onClick={() => props.cancel()}
ariaLabel={translate('meetingPage.cancel.ariaLabel')}
>
<FormattedMessage id="meetingPage.cancel" />
</DefaultButton>
</Stack>
</StackItem>
</div>
);
}
Example #25
Source File: MeetingPage.tsx From msteams-meetings-template with MIT License | 4 votes |
function DateTimePicker(props: DateTimePickerProps) {
function getDatePickerStrings(): IDatePickerStrings {
const localeData = moment.localeData();
return {
months: localeData.months(),
shortMonths: localeData.monthsShort(),
days: localeData.weekdays(),
shortDays: localeData.weekdaysMin(),
goToToday: translate('datePicker.goToToday'),
prevMonthAriaLabel: translate('datePicker.previousMonth.ariaLabel'),
nextMonthAriaLabel: translate('datePicker.nextMonth.ariaLabel'),
prevYearAriaLabel: translate('datePicker.previousYear.ariaLabel'),
nextYearAriaLabel: translate('datePicker.nextYear.ariaLabel'),
closeButtonAriaLabel: translate('datePicker.close.ariaLabel'),
};
}
function onDayPicked(date: Date | null | undefined) {
const currentDateTime = moment(props.dateTime);
const offsetFromStartOfDay = currentDateTime.diff(
moment(currentDateTime).startOf('day')
);
const newDateTime = moment(date ?? currentDateTime)
.startOf('day')
.add(offsetFromStartOfDay);
props.onTimeUpdated(newDateTime);
}
function onTimePicked(
event: React.FormEvent<IComboBox>,
option?: IComboBoxOption,
index?: number,
value?: string
) {
const currentDateTimeStartOfDay = moment(props.dateTime).startOf('day');
let newDateTime: moment.Moment;
if (option) {
const offsetFromStartOfDay = moment.duration(option.key, 'minutes');
newDateTime = currentDateTimeStartOfDay.add(offsetFromStartOfDay);
} else {
// User entered a free-form string, try to parse it as a time
const enteredTime = moment(value, timePickerFormat);
if (enteredTime.isValid()) {
const offsetFromStartOfDay = enteredTime.diff(
moment(enteredTime).startOf('day')
);
newDateTime = currentDateTimeStartOfDay.add(offsetFromStartOfDay);
} else {
newDateTime = moment(props.dateTime);
}
}
props.onTimeUpdated(newDateTime);
}
function onFormatDate(dateToFormat?: Date): string {
return moment(dateToFormat).format(datePickerFormat);
}
function onParseDateFromString(value: string): Date {
return moment(value, datePickerFormat).toDate();
}
const timeSuggestions = _.range(0, 1440, 30).map(minutes => {
// if the selection is before the min value
const projectedEndTime = moment(props.dateTime)
.startOf('day')
.add(moment.duration(minutes, 'minutes'));
const isDisabled = moment(props.minDate).isAfter(projectedEndTime);
const timeTag = moment()
.startOf('day')
.minutes(minutes)
.format(timePickerFormat);
const projectedDuration = moment.duration(
moment(projectedEndTime).diff(props.minDate)
);
const projectedDurationString = _.trim(formatDuration(projectedDuration));
return {
key: minutes,
text:
props.includeDuration &&
!isDisabled &&
projectedDurationString.length > 0
? `${timeTag} (${projectedDurationString})`
: timeTag,
disabled: isDisabled
};
});
return (
<Stack horizontal>
<DatePicker
className="newMeetingDatePicker"
borderless
firstDayOfWeek={moment.localeData().firstDayOfWeek() as DayOfWeek}
strings={getDatePickerStrings()}
value={props.dateTime?.toDate()}
formatDate={onFormatDate}
parseDateFromString={onParseDateFromString}
onSelectDate={onDayPicked}
minDate={props.minDate?.toDate()}
/>
<ComboBox
className="newMeetingComboBox"
styles={{ root: { maxHeight: '500px' } }}
useComboBoxAsMenuWidth={!props.includeDuration}
scrollSelectedToTop={true}
allowFreeform={true}
autoComplete="on"
options={timeSuggestions}
onChange={onTimePicked}
text={props.dateTime?.format(timePickerFormat)}
/>
{props.iconName === 'ReplyAlt' ? (
<FontIcon className="newMeetingPickerIcon" iconName={props.iconName} />
) : (
<Text className="newMeetingPickerIncrement" variant="smallPlus">
{formatDuration(
moment.duration(moment(props.dateTime).diff(moment(props.minDate)))
)}
</Text>
)}
</Stack>
);
}