<commit_before>import React, {useState}                  from "react";
import styled                 from "styled-components";
import T                      from "prop-types";
import { FontAwesomeIcon }    from '@fortawesome/react-fontawesome'
import moment                 from 'moment'

import STYLE                  from "../styling/Variables"
import AddressLine            from "./AddressLine";
import EventTimes             from "./EventTimes";
import EventRegistrationInfo  from "./EventRegistrationInfo";
import { ROUTEPLANNERS }      from "../../constants/URLs.js"
import { NAMES }              from "../../constants/Categories"
import i18n                   from "../../i18n";
import OpeningHours from "./OpeningHours"

const Tags = (tags=[], onClick, clickable) =>
  <TagsWrapper key="tags">
    <TagList>
    { tags
        .filter(t => t != "")
        .map( (t,index) =>
          <Tag key={index}>
            <TagLink onClick={ () => onClick(t) } clickable={clickable}>#{t}</TagLink>
          </Tag>
        )}
    </TagList>
  </TagsWrapper>

const getHomepageLink = (entry, t) => {
  if(!entry.homepage) return '';
  let shortLink = entry.homepage.replace( /^http(s)*:\/\/(www\.)*|\/$/gi , "");
  if(shortLink.length>30) shortLink = shortLink.split('/')[0] + "/…";
  if(shortLink.length>30) shortLink = i18n.t("entryDetails.homepagePlaceholder");
  const label = shortLink;
  return <EntryLink href={entry.homepage} target="_blank">{ label }</EntryLink>;
};

const getMailLink = (entry) => {
  const mail = entry.email
  if (!mail) {
    return "";
  }
  const label = (mail.length > 30) ? "E-Mail" : mail;
  return <EntryLink href={ "mailto:" + entry.email}>{ label }</EntryLink>;
};

const getTelLink = (entry) => {
  if(!entry.telephone) return null
  const tel = entry.telephone
  let url = "tel:" + tel.replace(/[^0-9+]/g,'')
  return <EntryLink href={url}>{tel}</EntryLink>
};

const getRoutePlannerLink = (entry) => {
  let url = '';
  let provider = '';
  if( /iPhone|iPad|iPod/i.test(navigator.userAgent) ) provider = "apple"
  else if( navigator.userAgent.toLowerCase().indexOf("android") !== -1 ) provider = "android"
  else provider = 'default'

  if( provider === "apple" || provider === "default") {
    url = ROUTEPLANNERS[provider].link.replace("{addr}",entry.street + "+" + entry.zip + "+" + entry.city)
  }
  else url = ROUTEPLANNERS[provider].link.replace('{lat}',entry.lat).replace('{lng}',entry.lng)

  return(
    <EntryLink
      title={ "Hinfinden mit "+ROUTEPLANNERS[provider].name }
      href={url} target="_blank">
      {i18n.t("entryDetails.route")}
    </EntryLink>
  )
};

const BusinessCard = ({ entry, hasImage, t, isEvent, onTag, tagsClickable }) => {
  // TODO: make the length of brief description dynamic from .env
  // TODO: be careful it should be consistent with the hard limit from EntryForm
  const briefDescriptionLength = 250
  const isDescriptionTooLong = entry.description.length > briefDescriptionLength

  const [showFulldescription, setShowMoreDescription] = useState(false)

  const getDescription = () => {
    const {description} = entry

    if (isDescriptionTooLong && !showFulldescription) {
      // the extra space is to separate the read-more link from the actual description
      return description.substr(0, briefDescriptionLength) + '... '
    }

    return description
  }

  if (!entry) {
    return(
      <LoadingEntryMessage>
        {i18n.t("entryDetails.loadingEntry")}
      </LoadingEntryMessage>
    );
  }
  else {
    const categoryName = NAMES[entry.categories && entry.categories[0]]
    return (
      <EntryDetailPage hasImage={hasImage}>
        <EntryCategory category={categoryName}>
          <span>
            { i18n.t("category." + categoryName) }
          </span>
        </EntryCategory>
        <EntryTitle>{entry.title}</EntryTitle>
        { isEvent ? <EventTimes start={ entry.start } end={ entry.end } showTimes={ true }/> : "" }
        <EntryDescription>
          {getDescription()}
          {
            isDescriptionTooLong && !showFulldescription &&
            <FlatButon onClick={() => setShowMoreDescription(true)}>{i18n.t("entryDetails.readMore")}</FlatButon>
          }
        </EntryDescription>

        <Hr />

        <EntryDetailsOtherData>{[
          ((entry.organizer) ?
            <div key="organizer">
              <FontAwesomeIconElement icon="user" />
              { entry.organizer }
            </div> : null),
          ((entry.homepage && entry.registration !== "homepage") ?
            <div key="hp">
              <FontAwesomeIconElement icon="globe-africa" />
              { getHomepageLink(entry, t) }
            </div> : null),
          ((entry.email && entry.registration !== "email") ?
            <div key="mail">
              <FontAwesomeIconElement icon="envelope" />
              { getMailLink(entry) }
            </div>
            : null),
          ((entry.telephone && entry.registration !== "telephone")
            ?
            <div key="tel">
              <FontAwesomeIconElement icon="phone" />{ getTelLink(entry) }
            </div>
            : null),
          ((entry.street && entry.zip && entry.city) ?
            <React.Fragment>
              <div key="addr">
                <div key="addr" className="address pure-g">
                  <FontAwesomeIconElement className="pure-u-2-24" icon="map-marker-alt" />
                  <AddressWrapper className="pure-u-22-24">
                    <AddressLine { ...entry } />
                  </AddressWrapper>
                </div>
                <div key="route">
                  <FontAwesomeIconElement icon="route" />
                  { getRoutePlannerLink(entry) }
                </div></div>
              <Hr />
            </React.Fragment>
            : null),
          (<OpeningHours oh="Tu 00:15-04:15" />),
          (<Hr />),
          (entry.tags && entry.tags.filter(t => t !="").length > 0<commit_msg>feat: make the opening hours dynamic<commit_after>import React, {useState}                  from "react";
import styled                 from "styled-components";
import T                      from "prop-types";
import { FontAwesomeIcon }    from '@fortawesome/react-fontawesome'
import moment                 from 'moment'

import STYLE                  from "../styling/Variables"
import AddressLine            from "./AddressLine";
import EventTimes             from "./EventTimes";
import EventRegistrationInfo  from "./EventRegistrationInfo";
import { ROUTEPLANNERS }      from "../../constants/URLs.js"
import { NAMES }              from "../../constants/Categories"
import i18n                   from "../../i18n";
import OpeningHours from "./OpeningHours"

const Tags = (tags=[], onClick, clickable) =>
  <TagsWrapper key="tags">
    <TagList>
    { tags
        .filter(t => t != "")
        .map( (t,index) =>
          <Tag key={index}>
            <TagLink onClick={ () => onClick(t) } clickable={clickable}>#{t}</TagLink>
          </Tag>
        )}
    </TagList>
  </TagsWrapper>

const getHomepageLink = (entry, t) => {
  if(!entry.homepage) return '';
  let shortLink = entry.homepage.replace( /^http(s)*:\/\/(www\.)*|\/$/gi , "");
  if(shortLink.length>30) shortLink = shortLink.split('/')[0] + "/…";
  if(shortLink.length>30) shortLink = i18n.t("entryDetails.homepagePlaceholder");
  const label = shortLink;
  return <EntryLink href={entry.homepage} target="_blank">{ label }</EntryLink>;
};

const getMailLink = (entry) => {
  const mail = entry.email
  if (!mail) {
    return "";
  }
  const label = (mail.length > 30) ? "E-Mail" : mail;
  return <EntryLink href={ "mailto:" + entry.email}>{ label }</EntryLink>;
};

const getTelLink = (entry) => {
  if(!entry.telephone) return null
  const tel = entry.telephone
  let url = "tel:" + tel.replace(/[^0-9+]/g,'')
  return <EntryLink href={url}>{tel}</EntryLink>
};

const getRoutePlannerLink = (entry) => {
  let url = '';
  let provider = '';
  if( /iPhone|iPad|iPod/i.test(navigator.userAgent) ) provider = "apple"
  else if( navigator.userAgent.toLowerCase().indexOf("android") !== -1 ) provider = "android"
  else provider = 'default'

  if( provider === "apple" || provider === "default") {
    url = ROUTEPLANNERS[provider].link.replace("{addr}",entry.street + "+" + entry.zip + "+" + entry.city)
  }
  else url = ROUTEPLANNERS[provider].link.replace('{lat}',entry.lat).replace('{lng}',entry.lng)

  return(
    <EntryLink
      title={ "Hinfinden mit "+ROUTEPLANNERS[provider].name }
      href={url} target="_blank">
      {i18n.t("entryDetails.route")}
    </EntryLink>
  )
};

const BusinessCard = ({ entry, hasImage, t, isEvent, onTag, tagsClickable }) => {
  // TODO: make the length of brief description dynamic from .env
  // TODO: be careful it should be consistent with the hard limit from EntryForm
  const briefDescriptionLength = 250
  const isDescriptionTooLong = entry.description.length > briefDescriptionLength

  const [showFulldescription, setShowMoreDescription] = useState(false)

  const getDescription = () => {
    const {description} = entry

    if (isDescriptionTooLong && !showFulldescription) {
      // the extra space is to separate the read-more link from the actual description
      return description.substr(0, briefDescriptionLength) + '... '
    }

    return description
  }

  if (!entry) {
    return(
      <LoadingEntryMessage>
        {i18n.t("entryDetails.loadingEntry")}
      </LoadingEntryMessage>
    );
  }
  else {
    const categoryName = NAMES[entry.categories && entry.categories[0]]
    return (
      <EntryDetailPage hasImage={hasImage}>
        <EntryCategory category={categoryName}>
          <span>
            { i18n.t("category." + categoryName) }
          </span>
        </EntryCategory>
        <EntryTitle>{entry.title}</EntryTitle>
        { isEvent ? <EventTimes start={ entry.start } end={ entry.end } showTimes={ true }/> : "" }
        <EntryDescription>
          {getDescription()}
          {
            isDescriptionTooLong && !showFulldescription &&
            <FlatButon onClick={() => setShowMoreDescription(true)}>{i18n.t("entryDetails.readMore")}</FlatButon>
          }
        </EntryDescription>

        <Hr />

        <EntryDetailsOtherData>{[
          ((entry.organizer) ?
            <div key="organizer">
              <FontAwesomeIconElement icon="user" />
              { entry.organizer }
            </div> : null),
          ((entry.homepage && entry.registration !== "homepage") ?
            <div key="hp">
              <FontAwesomeIconElement icon="globe-africa" />
              { getHomepageLink(entry, t) }
            </div> : null),
          ((entry.email && entry.registration !== "email") ?
            <div key="mail">
              <FontAwesomeIconElement icon="envelope" />
              { getMailLink(entry) }
            </div>
            : null),
          ((entry.telephone && entry.registration !== "telephone")
            ?
            <div key="tel">
              <FontAwesomeIconElement icon="phone" />{ getTelLink(entry) }
            </div>
            : null),
          ((entry.street && entry.zip && entry.city) ?
            <React.Fragment>
              <div key="addr">
                <div key="addr" className="address pure-g">
                  <FontAwesomeIconElement className="pure-u-2-24" icon="map-marker-alt" />
                  <AddressWrapper className="pure-u-22-24">
                    <AddressLine { ...entry } />
                  </AddressWrapper>
                </div>
                <div key="route">
                  <FontAwesomeIconElement icon="route" />
                  { getRoutePlannerLink(entry) }
                </div></div>
              <Hr />
            </React.Fragment>
            : null),
          (entry.opening_hours &&
            <React.Fragment>
              <OpeningHours oh={entry.opening_hours} />
              <Hr />
            </React.Fragment>
          ),
          (entry.tags && entry.tags.filter(t => t !="").length > 0
{'fraction_non_alphanumeric': 0.154433742942544, 'fraction_numerical': 0.006808369312520757, 'mean_word_length': 2.24313408723748, 'pattern_counts': {'":': 0, '<': 125, '<?xml version=': 0, '>': 159, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2630514', 'n_tokens_mistral': 3618, 'n_tokens_neox': 3499, 'n_words': 736}