@trii/components 2.0.25 → 2.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -8661,19 +8661,19 @@ const ButtonsContainer = material.styled(material.Box)(({ theme }) => ({
8661
8661
  const SmallIconButton = material.styled(material.IconButton)({
8662
8662
  padding: 4,
8663
8663
  });
8664
- const HeaderContainer = material.styled(material.Box)({
8664
+ const HeaderContainer$1 = material.styled(material.Box)({
8665
8665
  display: 'flex',
8666
8666
  flexDirection: 'column',
8667
8667
  alignItems: 'center',
8668
8668
  marginBottom: '16px',
8669
8669
  position: 'relative',
8670
8670
  });
8671
- const ContactAvatar = material.styled(material.Avatar)({
8671
+ const ContactAvatar$1 = material.styled(material.Avatar)({
8672
8672
  width: 60,
8673
8673
  height: 60,
8674
8674
  marginBottom: 8,
8675
8675
  });
8676
- const ContactName = material.styled(material.Typography)({
8676
+ const ContactName$1 = material.styled(material.Typography)({
8677
8677
  whiteSpace: 'nowrap',
8678
8678
  overflow: 'hidden',
8679
8679
  textOverflow: 'ellipsis',
@@ -8688,7 +8688,7 @@ const LoadingContainer = material.styled(material.Box)({
8688
8688
  height: 60,
8689
8689
  marginBottom: 8,
8690
8690
  });
8691
- const Header = ({ imgUrl, name, contactId, navigate, isLoading = false, onError, onClose, isBusiness = false, }) => {
8691
+ const Header$1 = ({ imgUrl, name, contactId, navigate, isLoading = false, onError, onClose, isBusiness = false, }) => {
8692
8692
  const handleNavigation = React.useCallback((url) => (event) => {
8693
8693
  try {
8694
8694
  event.preventDefault();
@@ -8714,7 +8714,7 @@ const Header = ({ imgUrl, name, contactId, navigate, isLoading = false, onError,
8714
8714
  const handleNavigateToConversations = handleNavigation('/a/conversations/conversations');
8715
8715
  const displayName = name || 'Unknown Contact';
8716
8716
  const avatarAlt = `Avatar for ${displayName}`;
8717
- return (jsxRuntimeExports.jsxs(HeaderContainer, { children: [jsxRuntimeExports.jsxs(ButtonsContainer, { children: [jsxRuntimeExports.jsx(SmallIconButton, { color: "info", size: "small", onClick: (e) => {
8717
+ return (jsxRuntimeExports.jsxs(HeaderContainer$1, { children: [jsxRuntimeExports.jsxs(ButtonsContainer, { children: [jsxRuntimeExports.jsx(SmallIconButton, { color: "info", size: "small", onClick: (e) => {
8718
8718
  handleNavigateToContacts(e);
8719
8719
  onClose();
8720
8720
  }, onMouseDown: (e) => {
@@ -8732,7 +8732,7 @@ const Header = ({ imgUrl, name, contactId, navigate, isLoading = false, onError,
8732
8732
  handleNavigateToConversations(e);
8733
8733
  onClose();
8734
8734
  }
8735
- }, "aria-label": "Go to conversations", children: jsxRuntimeExports.jsx(default_1, { fontSize: "small" }) })] }), isLoading ? (jsxRuntimeExports.jsx(LoadingContainer, { children: jsxRuntimeExports.jsx(material.CircularProgress, { size: 24 }) })) : (jsxRuntimeExports.jsx(ContactAvatar, { src: imgUrl, alt: avatarAlt, onError: () => onError?.(new Error('Failed to load avatar')) })), jsxRuntimeExports.jsx(ContactName, { variant: "h6", title: displayName, children: displayName })] }));
8735
+ }, "aria-label": "Go to conversations", children: jsxRuntimeExports.jsx(default_1, { fontSize: "small" }) })] }), isLoading ? (jsxRuntimeExports.jsx(LoadingContainer, { children: jsxRuntimeExports.jsx(material.CircularProgress, { size: 24 }) })) : (jsxRuntimeExports.jsx(ContactAvatar$1, { src: imgUrl, alt: avatarAlt, onError: () => onError?.(new Error('Failed to load avatar')) })), jsxRuntimeExports.jsx(ContactName$1, { variant: "h6", title: displayName, children: displayName })] }));
8736
8736
  };
8737
8737
 
8738
8738
  const Container$1 = material.styled(material.Box)({
@@ -14671,7 +14671,7 @@ const LabelsSection = ({ contactData, title }) => {
14671
14671
  * @param obj The object to check
14672
14672
  * @returns True if the object is an IContact
14673
14673
  */
14674
- function isContact(obj) {
14674
+ function isContact$1(obj) {
14675
14675
  // Si está marcado explícitamente como negocio, no es un contacto regular
14676
14676
  if (obj?.isBusiness === true) {
14677
14677
  return false;
@@ -14697,7 +14697,7 @@ const SectionTitle$1 = material.styled(material.Typography)({
14697
14697
  borderBottom: `1px solid lightgray`,
14698
14698
  });
14699
14699
  const BusinessSection = ({ contactData, title }) => {
14700
- if (!contactData || !isContact(contactData))
14700
+ if (!contactData || !isContact$1(contactData))
14701
14701
  return null;
14702
14702
  return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(SectionTitle$1, { gutterBottom: true, mt: 2, variant: "subtitle1", children: title }), jsxRuntimeExports.jsx(material.Typography, { variant: "body2", color: "text.secondary", children: contactData?.businessName })] }));
14703
14703
  };
@@ -14707,7 +14707,7 @@ const BusinessSection = ({ contactData, title }) => {
14707
14707
  * @param obj The object to check
14708
14708
  * @returns True if the object is an IBusiness
14709
14709
  */
14710
- function isBusiness(obj) {
14710
+ function isBusiness$1(obj) {
14711
14711
  if (obj?.isBusiness === true) {
14712
14712
  // Si se ha marcado explícitamente como negocio con la propiedad isBusiness
14713
14713
  return true;
@@ -14757,7 +14757,7 @@ const SectionTitle = material.styled(material.Typography)({
14757
14757
  borderBottom: `1px solid lightgray`,
14758
14758
  });
14759
14759
  const MembersSection = ({ contactData, title, navigate }) => {
14760
- if (!contactData || !isBusiness(contactData) || !contactData.members?.length)
14760
+ if (!contactData || !isBusiness$1(contactData) || !contactData.members?.length)
14761
14761
  return null;
14762
14762
  return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(SectionTitle, { gutterBottom: true, mt: 2, variant: "subtitle1", children: title }), contactData?.members.map((member) => (jsxRuntimeExports.jsx(MemberItem, { memberId: String(member.id), name: member.name, navigate: navigate }, member.id)))] }));
14763
14763
  };
@@ -14798,8 +14798,8 @@ const ContactInfoPopup = ({ open, anchorEl, onClose, contactData, avatarImgUrl,
14798
14798
  view: 'Ver',
14799
14799
  email: 'Correo Electrónico',
14800
14800
  }[key] || key), }) => {
14801
- const dataIsBusiness = isBusiness(contactData);
14802
- const dataIsContact = isContact(contactData);
14801
+ const dataIsBusiness = isBusiness$1(contactData);
14802
+ const dataIsContact = isContact$1(contactData);
14803
14803
  const contactMethods = [
14804
14804
  {
14805
14805
  icon: jsxRuntimeExports.jsx(PhoneEnabled, { fontSize: "small" }),
@@ -14848,8 +14848,236 @@ const ContactInfoPopup = ({ open, anchorEl, onClose, contactData, avatarImgUrl,
14848
14848
  window.removeEventListener('keydown', handleKeyDown);
14849
14849
  };
14850
14850
  }, [open, onClose]);
14851
- return (jsxRuntimeExports.jsx(material.Popper, { sx: { zIndex: 1300 }, open: open, anchorEl: anchorEl, placement: "bottom-start", "data-popper-child": "true", children: jsxRuntimeExports.jsx(material.ClickAwayListener, { onClickAway: onClose, children: jsxRuntimeExports.jsx(PopupContainer, { children: jsxRuntimeExports.jsxs(material.CardContent, { children: [jsxRuntimeExports.jsx(Header, { navigate: navigate, contactId: contactData?.id, imgUrl: avatarImgUrl, name: contactData?.name, onClose: onClose, isBusiness: dataIsBusiness }), jsxRuntimeExports.jsx(LabelsSection, { contactData: contactData, title: t('labels') }), dataIsContact && (jsxRuntimeExports.jsx(BusinessSection, { contactData: contactData, title: t('business') })), dataIsBusiness && (jsxRuntimeExports.jsx(MembersSection, { contactData: contactData, title: t('businessMembers'), navigate: navigate })), contactMethods.map((method, index) => (jsxRuntimeExports.jsx(ContactMethod, { icon: method.icon, title: method.title, contactList: method.contactList, showTitle: method.showTitle }, index))), jsxRuntimeExports.jsx(Properties, { properties: contactData?.properties, title: t('properties') })] }) }) }) }));
14851
+ return (jsxRuntimeExports.jsx(material.Popper, { sx: { zIndex: 1300 }, open: open, anchorEl: anchorEl, placement: "bottom-start", "data-popper-child": "true", children: jsxRuntimeExports.jsx(material.ClickAwayListener, { onClickAway: onClose, children: jsxRuntimeExports.jsx(PopupContainer, { children: jsxRuntimeExports.jsxs(material.CardContent, { children: [jsxRuntimeExports.jsx(Header$1, { navigate: navigate, contactId: contactData?.id, imgUrl: avatarImgUrl, name: contactData?.name, onClose: onClose, isBusiness: dataIsBusiness }), jsxRuntimeExports.jsx(LabelsSection, { contactData: contactData, title: t('labels') }), dataIsContact && (jsxRuntimeExports.jsx(BusinessSection, { contactData: contactData, title: t('business') })), dataIsBusiness && (jsxRuntimeExports.jsx(MembersSection, { contactData: contactData, title: t('businessMembers'), navigate: navigate })), contactMethods.map((method, index) => (jsxRuntimeExports.jsx(ContactMethod, { icon: method.icon, title: method.title, contactList: method.contactList, showTitle: method.showTitle }, index))), jsxRuntimeExports.jsx(Properties, { properties: contactData?.properties, title: t('properties') })] }) }) }) }));
14852
+ };
14853
+
14854
+ const HeaderContainer = material.styled(material.Box)({
14855
+ display: 'flex',
14856
+ flexDirection: 'column',
14857
+ alignItems: 'center',
14858
+ marginBottom: '16px',
14859
+ position: 'relative',
14860
+ });
14861
+ const ContactAvatar = material.styled(material.Avatar)({
14862
+ width: 60,
14863
+ height: 60,
14864
+ marginBottom: 8,
14865
+ });
14866
+ const ContactName = material.styled(material.Typography)({
14867
+ whiteSpace: 'nowrap',
14868
+ overflow: 'hidden',
14869
+ textOverflow: 'ellipsis',
14870
+ maxWidth: 200,
14871
+ textAlign: 'center',
14872
+ });
14873
+ const Header = ({ imgUrl, displayName = 'Unknown Contact', onError, }) => {
14874
+ const avatarAlt = `Avatar for ${displayName}`;
14875
+ return (jsxRuntimeExports.jsxs(HeaderContainer, { children: [jsxRuntimeExports.jsx(ContactAvatar, { src: imgUrl, alt: avatarAlt, onError: () => onError?.(new Error('Failed to load avatar')) }), jsxRuntimeExports.jsx(ContactName, { variant: "h6", title: displayName, children: displayName })] }));
14876
+ };
14877
+
14878
+ class ApiError extends Error {
14879
+ status;
14880
+ body;
14881
+ constructor(message, status, body) {
14882
+ super(message);
14883
+ this.name = 'ApiError';
14884
+ this.status = status;
14885
+ this.body = body;
14886
+ }
14887
+ }
14888
+ async function requestJson({ url, method = 'GET', headers, body, signal, }) {
14889
+ const res = await globalThis.fetch(url, {
14890
+ method,
14891
+ headers: {
14892
+ ...(body ? { 'Content-Type': 'application/json' } : {}),
14893
+ ...(headers ?? {}),
14894
+ },
14895
+ body: body ? JSON.stringify(body) : undefined,
14896
+ signal,
14897
+ });
14898
+ const contentType = res.headers.get('content-type') || '';
14899
+ const isJson = contentType.includes('application/json');
14900
+ const parsedBody = isJson ? await res.json().catch(() => null) : await res.text().catch(() => null);
14901
+ if (!res.ok) {
14902
+ const message = typeof parsedBody === 'object' && parsedBody && 'message' in parsedBody
14903
+ ? String(parsedBody.message)
14904
+ : `Request failed with status ${res.status}`;
14905
+ throw new ApiError(message, res.status, parsedBody);
14906
+ }
14907
+ return parsedBody;
14908
+ }
14909
+
14910
+ function joinUrl(baseUrl, path) {
14911
+ const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
14912
+ const normalizedPath = path.startsWith('/') ? path : `/${path}`;
14913
+ return `${normalizedBase}${normalizedPath}`;
14914
+ }
14915
+ async function fetchContact({ baseUrl, contactId, signal }) {
14916
+ const url = joinUrl(baseUrl, `/contacts/${encodeURIComponent(contactId)}`);
14917
+ return requestJson({ url, signal });
14918
+ }
14919
+
14920
+ /**
14921
+ * Type guard to check if an object is an IBusiness
14922
+ * @param obj The object to check
14923
+ * @returns True if the object is an IBusiness
14924
+ */
14925
+ function isBusiness(obj) {
14926
+ if (obj?.isBusiness === true) {
14927
+ // Si se ha marcado explícitamente como negocio con la propiedad isBusiness
14928
+ return true;
14929
+ }
14930
+ return (obj !== null &&
14931
+ typeof obj === 'object' &&
14932
+ typeof obj.id === 'string' &&
14933
+ typeof obj.spaceId === 'string' &&
14934
+ typeof obj.name === 'string' &&
14935
+ Array.isArray(obj.membersId) &&
14936
+ Array.isArray(obj.members) &&
14937
+ Array.isArray(obj.phones) &&
14938
+ Array.isArray(obj.emails) &&
14939
+ typeof obj.imageUrl === 'string' &&
14940
+ !('firstName' in obj) &&
14941
+ !('lastName' in obj));
14942
+ }
14943
+
14944
+ /**
14945
+ * Type guard to check if an object is an IContact
14946
+ * @param obj The object to check
14947
+ * @returns True if the object is an IContact
14948
+ */
14949
+ function isContact(obj) {
14950
+ // Si está marcado explícitamente como negocio, no es un contacto regular
14951
+ if (obj?.isBusiness === true) {
14952
+ return false;
14953
+ }
14954
+ return (obj !== null &&
14955
+ typeof obj === 'object' &&
14956
+ typeof obj.id === 'string' &&
14957
+ typeof obj.spaceId === 'string' &&
14958
+ typeof obj.name === 'string' &&
14959
+ typeof obj.firstName === 'string' &&
14960
+ typeof obj.lastName === 'string' &&
14961
+ Array.isArray(obj.phones) &&
14962
+ Array.isArray(obj.emails) &&
14963
+ 'origin' in obj &&
14964
+ typeof obj.isSpam === 'boolean' &&
14965
+ (!obj.businessId || typeof obj.businessId === 'string'));
14966
+ }
14967
+
14968
+ function useEditContactModalController({ open, baseUrl, contactId, }) {
14969
+ const abortRef = React.useRef(null);
14970
+ const [state, setState] = React.useState({
14971
+ isLoading: false,
14972
+ error: null,
14973
+ contactData: null,
14974
+ });
14975
+ const canFetch = React.useMemo(() => Boolean(open && baseUrl && contactId), [open, baseUrl, contactId]);
14976
+ React.useEffect(() => {
14977
+ if (open)
14978
+ return;
14979
+ abortRef.current?.abort();
14980
+ setState({ isLoading: false, error: null, contactData: null });
14981
+ }, [open]);
14982
+ React.useEffect(() => {
14983
+ if (!canFetch) {
14984
+ return;
14985
+ }
14986
+ abortRef.current?.abort();
14987
+ const controller = new AbortController();
14988
+ abortRef.current = controller;
14989
+ setState({ isLoading: true, error: null, contactData: null });
14990
+ fetchContact({ baseUrl: baseUrl, contactId: contactId, signal: controller.signal })
14991
+ .then((data) => {
14992
+ setState({ isLoading: false, error: null, contactData: data });
14993
+ })
14994
+ .catch((err) => {
14995
+ if (controller.signal.aborted)
14996
+ return;
14997
+ setState((prev) => ({ ...prev, isLoading: false, error: err }));
14998
+ });
14999
+ return () => {
15000
+ controller.abort();
15001
+ };
15002
+ }, [canFetch, baseUrl, contactId]);
15003
+ const selectors = React.useMemo(() => {
15004
+ const contactData = state.contactData;
15005
+ const business = isBusiness(contactData);
15006
+ const contact = isContact(contactData);
15007
+ let contactType = 'unknown';
15008
+ if (business)
15009
+ contactType = 'business';
15010
+ if (contact)
15011
+ contactType = 'contact';
15012
+ let displayName = 'Unknown Contact';
15013
+ if (business) {
15014
+ displayName = contactData.name;
15015
+ }
15016
+ else if (contact) {
15017
+ displayName = `${contactData.firstName} ${contactData.lastName}`.trim();
15018
+ }
15019
+ return {
15020
+ isBusiness: business,
15021
+ isContact: contact,
15022
+ contactType,
15023
+ displayName,
15024
+ };
15025
+ }, [state.contactData]);
15026
+ return {
15027
+ state,
15028
+ selectors,
15029
+ actions: {
15030
+ setContactData: (contactData) => setState((prev) => ({ ...prev, contactData: contactData ?? null })),
15031
+ clearError: () => setState((prev) => ({ ...prev, error: null })),
15032
+ },
15033
+ };
15034
+ }
15035
+
15036
+ const EditContactModal = ({ open, onClose, baseUrl, contactId, sx,
15037
+ // t
15038
+ }) => {
15039
+ const { state, selectors } = useEditContactModalController({
15040
+ open,
15041
+ baseUrl,
15042
+ contactId,
15043
+ });
15044
+ const handleClose = (event, reason) => {
15045
+ if (reason === 'escapeKeyDown') {
15046
+ const maybeEvent = event;
15047
+ if (typeof maybeEvent?.stopPropagation === 'function') {
15048
+ maybeEvent.stopPropagation();
15049
+ }
15050
+ if (typeof maybeEvent?.preventDefault === 'function') {
15051
+ maybeEvent.preventDefault();
15052
+ }
15053
+ }
15054
+ onClose();
15055
+ };
15056
+ const baseSx = {
15057
+ position: 'absolute',
15058
+ top: '50%',
15059
+ left: '50%',
15060
+ transform: 'translate(-50%, -50%)',
15061
+ width: 'min(600px, calc(100vw - 32px))',
15062
+ bgcolor: 'background.paper',
15063
+ borderRadius: 2,
15064
+ boxShadow: 24,
15065
+ outline: 0,
15066
+ p: 2,
15067
+ };
15068
+ const mergedSx = Array.isArray(sx)
15069
+ ? [baseSx, ...sx]
15070
+ : sx
15071
+ ? [baseSx, sx]
15072
+ : baseSx;
15073
+ return (jsxRuntimeExports.jsx(material.Modal, { open: open, onClose: handleClose, closeAfterTransition: true, slots: { backdrop: material.Backdrop }, slotProps: { backdrop: { timeout: 200 } }, children: jsxRuntimeExports.jsx(material.Fade, { in: open, timeout: 200, children: jsxRuntimeExports.jsx(material.Box, { sx: mergedSx, children: state.isLoading && !state.contactData ? (jsxRuntimeExports.jsx(material.Box, { sx: {
15074
+ display: 'flex',
15075
+ justifyContent: 'center',
15076
+ alignItems: 'center',
15077
+ minHeight: 180,
15078
+ }, children: jsxRuntimeExports.jsx(material.CircularProgress, {}) })) : state.error ? (jsxRuntimeExports.jsx(material.Box, { sx: { mb: 2 }, children: "Failed to load contact" })) : state.contactData ? (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(Header, { imgUrl: state.contactData.imageUrl, displayName: selectors.displayName }), jsxRuntimeExports.jsx(material.Box, { sx: { minHeight: 120 } })] })) : null }) }) }));
14852
15079
  };
14853
15080
 
14854
15081
  exports.ContactInfoPopup = ContactInfoPopup;
15082
+ exports.EditContactModal = EditContactModal;
14855
15083
  //# sourceMappingURL=index.js.map