<commit_before>import React, { useState, useCallback } from "react";
import PropTypes from "prop-types";
import styled from "styled-components";
import style from "@agir/front/genericComponents/_variables.scss";
import { RawFeatherIcon } from "@agir/front/genericComponents/FeatherIcon";
import Avatar from "@agir/front/genericComponents/Avatar";

const Assets = styled.div`
  margin-left: 3rem;
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
`;

const Asset = styled.div`
  border: 1px solid #ddd;
  padding: 4px 10px;
  margin-right: 4px;
  margin-bottom: 4px;
  display: inline-block;
  font-size: 12px;
`;

const Name = styled.span``;

const Role = styled.span`
  color: ${style.primary500};
`;

const Email = styled.span`
  color: ${style.black500};
`;

const MemberInfos = styled.div`
  display: inline-flex;
  flex-wrap: wrap;

  ${Name}, ${Role} {
    margin-right: 0.5rem;
  }
`;

const Member = styled.div`
  font-size: 1rem;

  > div:first-child {
    display: flex;
    flex-direction: row;
    align-items: center;
  }
`;

const ShowMore = styled.span`
  color: ${style.primary500};
  cursor: pointer;
  margin-bottom: 4px;
  margin-left: 4px;

  :hover {
    text-decoration: underline;
  }
`;

const MEMBERSHIP_TYPE_LABEL = {
  10: "Membre",
  50: "Gestionnaire",
  100: "Animateur·ice",
};

const GroupMember = (props) => {
  const { name, image = "", membershipType = 10, email, assets = [] } = props;

  const role = MEMBERSHIP_TYPE_LABEL[String(membershipType)];

  const [customAssets, setCustomAssets] = useState(
    assets?.length ? assets.slice(0, 3) : []
  );
  const [showMore, setShowMore] = useState(assets?.length > 3);

  const handleShowMore = useCallback(() => {
    setCustomAssets(assets);
    setShowMore(false);
  }, []);

  return (
    <>
      <Member>
        <div>
          {!!image && (
            <Avatar
              image={image}
              name={name}
              style={{
                width: "2rem",
                height: "2rem",
                padding: "0.25rem",
                borderRadius: "40px",
                marginRight: "1rem",
              }}
            />
          )}
          {!image && (
            <RawFeatherIcon
              name="user"
              style={{
                padding: "0.25rem",
                backgroundColor: style.primary500,
                color: "#fff",
                borderRadius: "40px",
                marginRight: "1rem",
              }}
            />
          )}
          <MemberInfos>
            <Name>{name}</Name>
            {role && <Role>({role})</Role>}
            <Email>{email}</Email>
          </MemberInfos>
        </div>
        {assets?.length > 0 && (
          <Assets>
            {customAssets.map((e, id) => (
              <Asset key={id}>{e}</Asset>
            ))}
            {showMore && <ShowMore onClick={handleShowMore}>Voir +</ShowMore>}
          </Assets>
        )}
      </Member>
    </>
  );
};
GroupMember.propTypes = {
  name: PropTypes.string,
  role: PropTypes.string,
  email: PropTypes.string,
  assets: PropTypes.arrayOf(PropTypes.string),
};

export default GroupMember;
<commit_msg>fix: use default avatar fallback in GroupMember component<commit_after>import PropTypes from "prop-types";
import React, { useState, useCallback } from "react";
import styled from "styled-components";

import style from "@agir/front/genericComponents/_variables.scss";

import Avatar from "@agir/front/genericComponents/Avatar";

const Assets = styled.div`
  margin-left: 3rem;
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
`;

const Asset = styled.div`
  border: 1px solid #ddd;
  padding: 4px 10px;
  margin-right: 4px;
  margin-bottom: 4px;
  display: inline-block;
  font-size: 12px;
`;

const Name = styled.span``;

const Role = styled.span`
  color: ${style.primary500};
`;

const Email = styled.span`
  color: ${style.black500};
`;

const MemberInfos = styled.div`
  display: inline-flex;
  flex-wrap: wrap;

  ${Name}, ${Role} {
    margin-right: 0.5rem;
  }
`;

const Member = styled.div`
  font-size: 1rem;

  > div:first-child {
    display: flex;
    flex-direction: row;
    align-items: center;
  }
`;

const ShowMore = styled.span`
  color: ${style.primary500};
  cursor: pointer;
  margin-bottom: 4px;
  margin-left: 4px;

  :hover {
    text-decoration: underline;
  }
`;

const MEMBERSHIP_TYPE_LABEL = {
  10: "Membre",
  50: "Gestionnaire",
  100: "Animateur·ice",
};

const GroupMember = (props) => {
  const { name, image = "", membershipType = 10, email, assets = [] } = props;
  const role = MEMBERSHIP_TYPE_LABEL[String(membershipType)];
  const [customAssets, setCustomAssets] = useState(
    assets?.length ? assets.slice(0, 3) : []
  );
  const [showMore, setShowMore] = useState(assets?.length > 3);
  const handleShowMore = useCallback(() => {
    setCustomAssets(assets);
    setShowMore(false);
  }, [assets]);

  return (
    <Member>
      <div>
        <Avatar
          image={image}
          name={name}
          style={{
            width: "2rem",
            height: "2rem",
            padding: "0.25rem",
            borderRadius: "40px",
            marginRight: "1rem",
          }}
        />
        <MemberInfos>
          <Name>{name}</Name>
          {role && <Role>({role})</Role>}
          <Email>{email}</Email>
        </MemberInfos>
      </div>
      {assets?.length > 0 && (
        <Assets>
          {customAssets.map((e, id) => (
            <Asset key={id}>{e}</Asset>
          ))}
          {showMore && <ShowMore onClick={handleShowMore}>Voir +</ShowMore>}
        </Assets>
      )}
    </Member>
  );
};
GroupMember.propTypes = {
  name: PropTypes.string,
  image: PropTypes.String,
  role: PropTypes.string,
  email: PropTypes.string,
  assets: PropTypes.arrayOf(PropTypes.string),
  membershipType: PropTypes.number,
};

export default GroupMember;

{'fraction_non_alphanumeric': 0.15069420927869961, 'fraction_numerical': 0.016423975618015577, 'mean_word_length': 2.412478336221837, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 56, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '7319411', 'n_tokens_mistral': 2013, 'n_tokens_neox': 1939, 'n_words': 409}