<commit_before>import React, { useEffect, useCallback } from "react";
import f from "lodash/fp";
import _ from "lodash";
import { Icon, Col, Row, Box, Text, Anchor } from "@tlon/indigo-react";
import moment from "moment";
import { Notifications, Rolodex, Timebox, IndexedNotification, Groups } from "~/types";
import { MOMENT_CALENDAR_DATE, daToUnix, resourceAsPath } from "~/logic/lib/util";
import { BigInteger } from "big-integer";
import GlobalApi from "~/logic/api/global";
import { Notification } from "./notification";
import { Associations } from "~/types";
import { cite } from '~/logic/lib/util';
import { InviteItem } from '~/views/components/Invite';
import { useWaitForProps } from "~/logic/lib/useWaitForProps";
import { useHistory } from "react-router-dom";

type DatedTimebox = [BigInteger, Timebox];

function filterNotification(associations: Associations, groups: string[]) {
  if (groups.length === 0) {
    return () => true;
  }
  return (n: IndexedNotification) => {
    if ("graph" in n.index) {
      const { group } = n.index.graph;
      return groups.findIndex((g) => group === g) !== -1;
    } else if ("group" in n.index) {
      const { group } = n.index.group;
      return groups.findIndex((g) => group === g) !== -1;
    } else if ("chat" in n.index) {
      const group = associations.chat[n.index.chat.chat]?.["group-path"];
      return groups.findIndex((g) => group === g) !== -1;
    }
    return true;
  };
}

export default function Inbox(props: {
  notifications: Notifications;
  archive: Notifications;
  groups: Groups;
  showArchive?: boolean;
  api: GlobalApi;
  associations: Associations;
  contacts: Rolodex;
  filter: string[];
  invites: any;
}) {
  const { api, associations, invites } = props;
  const waiter = useWaitForProps(props)
  const history = useHistory();
  useEffect(() => {
    let seen = false;
    setTimeout(() => {
      seen = true;
    }, 3000);
    return () => {
      if (seen) {
        api.hark.seen();
      }
    };
  }, []);

  const [newNotifications, ...notifications] =
    Array.from(props.showArchive ? props.archive : props.notifications) || [];

  const notificationsByDay = f.flow(
    f.map<DatedTimebox>(([date, nots]) => [
      date,
      nots.filter(filterNotification(associations, props.filter)),
    ]),
    f.groupBy<DatedTimebox>(([date]) =>
      moment(daToUnix(date)).format("DDMMYYYY")
    ),
    f.values
  )(notifications);

  useEffect(() => {
    api.hark.getMore(props.showArchive);
  }, [props.showArchive]);

  const onScroll = useCallback((e) => {
    let container = e.target;
    const { scrollHeight, scrollTop, clientHeight } = container;
    if((scrollHeight - scrollTop - clientHeight) < 20) {
      api.hark.getMore(props.showArchive);
    }
  }, [props.showArchive]);

  const acceptInvite = async (invite) => {
    const resource = {
      ship: `~${invite.resource.ship}`,
      name: invite.resource.name
    };
    await api.contacts.join(resource);
    await api.invite.accept('contacts', getKeyByValue(invites['contacts'], invite));
    const path = resourceAsPath(invite.resource)
    await waiter(p => path in p.associations?.contacts);

    history.push(`/~landscape${path}`);
  };

  const inviteItems = (invites, api) => {
    const returned = [];
    Object.keys(invites).map((appKey) => {
      const app = invites[appKey];
      Object.keys(app).map((uid) => {
        const invite = app[uid];
        const inviteItem =
          <InviteItem
            key={uid}
            invite={invite}
            onAccept={acceptInvite}
            onDecline={() => api.invite.decline(appKey, uid)}
          />;<commit_msg>inbox: redirect invites correctly<commit_after>import React, { useEffect, useCallback } from "react";
import f from "lodash/fp";
import _ from "lodash";
import { Icon, Col, Row, Box, Text, Anchor } from "@tlon/indigo-react";
import moment from "moment";
import { Notifications, Rolodex, Timebox, IndexedNotification, Groups } from "~/types";
import { MOMENT_CALENDAR_DATE, daToUnix, resourceAsPath } from "~/logic/lib/util";
import { BigInteger } from "big-integer";
import GlobalApi from "~/logic/api/global";
import { Notification } from "./notification";
import { Associations } from "~/types";
import { cite } from '~/logic/lib/util';
import { InviteItem } from '~/views/components/Invite';
import { useWaitForProps } from "~/logic/lib/useWaitForProps";
import { useHistory } from "react-router-dom";

type DatedTimebox = [BigInteger, Timebox];

function filterNotification(associations: Associations, groups: string[]) {
  if (groups.length === 0) {
    return () => true;
  }
  return (n: IndexedNotification) => {
    if ("graph" in n.index) {
      const { group } = n.index.graph;
      return groups.findIndex((g) => group === g) !== -1;
    } else if ("group" in n.index) {
      const { group } = n.index.group;
      return groups.findIndex((g) => group === g) !== -1;
    } else if ("chat" in n.index) {
      const group = associations.chat[n.index.chat.chat]?.["group-path"];
      return groups.findIndex((g) => group === g) !== -1;
    }
    return true;
  };
}

export default function Inbox(props: {
  notifications: Notifications;
  archive: Notifications;
  groups: Groups;
  showArchive?: boolean;
  api: GlobalApi;
  associations: Associations;
  contacts: Rolodex;
  filter: string[];
  invites: any;
}) {
  const { api, associations, invites } = props;
  const waiter = useWaitForProps(props)
  const history = useHistory();
  useEffect(() => {
    let seen = false;
    setTimeout(() => {
      seen = true;
    }, 3000);
    return () => {
      if (seen) {
        api.hark.seen();
      }
    };
  }, []);

  const [newNotifications, ...notifications] =
    Array.from(props.showArchive ? props.archive : props.notifications) || [];

  const notificationsByDay = f.flow(
    f.map<DatedTimebox>(([date, nots]) => [
      date,
      nots.filter(filterNotification(associations, props.filter)),
    ]),
    f.groupBy<DatedTimebox>(([date]) =>
      moment(daToUnix(date)).format("DDMMYYYY")
    ),
    f.values
  )(notifications);

  useEffect(() => {
    api.hark.getMore(props.showArchive);
  }, [props.showArchive]);

  const onScroll = useCallback((e) => {
    let container = e.target;
    const { scrollHeight, scrollTop, clientHeight } = container;
    if((scrollHeight - scrollTop - clientHeight) < 20) {
      api.hark.getMore(props.showArchive);
    }
  }, [props.showArchive]);

  const acceptInvite = (app: string, uid: string) => async (invite) => {
    const resource = {
      ship: `~${invite.resource.ship}`,
      name: invite.resource.name
    };

    let resourcePath = resourceAsPath(invite.resource);
    if(app === 'chat') {
      resourcePath = resourcePath.slice(5);
    }

    let path = `/home/resource/${app}${resourcePath}`;
    if(app === 'contacts') {
      await api.contacts.join(resource);
      path = resourceAsPath(invite.resource);
      await waiter(p => path in p.associations?.contacts);
    }
    await api.invite.accept(app, uid);

    history.push(`/~landscape${path}`);
  };

  const inviteItems = (invites, api) => {
    const returned = [];
    Object.keys(invites).map((appKey) => {
      const app = invites[appKey];
      Object.keys(app).map((uid) => {
        const invite = app[uid];
        const inviteItem =
          <InviteItem
            key={uid}
            invite={invite}
            onAccept={acceptInvite(appKey, uid)}
            onDecline={() => api.invite.decline(appKey, uid)}
          />;
{'fraction_non_alphanumeric': 0.16239883242669498, 'fraction_numerical': 0.0027862544779089825, 'mean_word_length': 3.187777777777778, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 46, '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': '3866322', 'n_tokens_mistral': 2467, 'n_tokens_neox': 2396, 'n_words': 538}