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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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>
                                    &nbsp;
                                </>
                            )
                        }
                    </Row>
                </div>
            </Container>
        </div>
    )
}
Example #5
Source File: DegreeInformations.tsx    From website with MIT License 5 votes vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 }}/>&nbsp;<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 vote down vote up
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 vote down vote up
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>
                                                &nbsp;&nbsp;
                                                <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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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">
                                &copy; 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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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>
  );
}