BioDrop icon indicating copy to clipboard operation
BioDrop copied to clipboard

[FEATURE] Group events together

Open eddiejaoude opened this issue 2 years ago • 23 comments

Description

On the community events page, we have duplicate events, but we can group them together and show multiple people attending them

I think stacking the avatars would look good

Screenshot 2023-01-02 at 22 01 21

https://tailwindui.com/components/application-ui/elements/avatars#component-00ccf3da2333eae32886bbc1d1ee362c

Screenshots

No response

Additional information

No response

eddiejaoude avatar Jan 02 '23 19:01 eddiejaoude

It's great having you contribute to this project

Welcome to the community :nerd_face:

If you would like to continue contributing to open source and would like to do it with an awesome inclusive community, you should join our Discord chat and our GitHub Organisation - we help and encourage each other to contribute to open source little and often 🤓 . Any questions let us know.

github-actions[bot] avatar Jan 02 '23 19:01 github-actions[bot]

@eddiejaoude Can I get this one?

ThorOnTheRocks avatar Jan 02 '23 21:01 ThorOnTheRocks

Sure, assigned to you 👍

eddiejaoude avatar Jan 02 '23 22:01 eddiejaoude

I am not sure what would be best to group them on, maybe the url?

eddiejaoude avatar Jan 02 '23 22:01 eddiejaoude

How far are you on this @ThorOnTheRocks? Do you mind an extra pair of hands on this? It would be lovely to know you and work with you!

thebarshablog avatar Jan 03 '23 12:01 thebarshablog

@eddiejaoude I guess grouping them on the url would be a good choice, showing only one card if it is the same event and the stacked avatar on the right corner. Regarding the UI I was already thinking about the stacked avatar from tailwind, it's the way to go I think.

@thebarshablog I haven't even started to be honest, my plan was to start later today after work but yeah that would be amazing actually to work together! We should split the tasks I guess like someone taking care of the UI and another about the logic perhaps? Just to avoid working on the same files maybe...I open to any suggestions really so what you think it's best!

ThorOnTheRocks avatar Jan 03 '23 12:01 ThorOnTheRocks

Sounds great! @ThorOnTheRocks. Are you open to getting over a GMeet or otherwise to speak elaboratively on it? Let me know, I'll make arrangements

thebarshablog avatar Jan 03 '23 13:01 thebarshablog

I was already thinking about the stacked avatar from tailwind, it's the way to go I think.

I have paid for the Tailwind components, so I can get you the code for that component to use on the project

export default function Example() {
  return (
    <>
      <div className="isolate flex -space-x-1 overflow-hidden">
        <img
          className="relative z-30 inline-block h-6 w-6 rounded-full ring-2 ring-white"
          src="https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
          alt=""
        />
        <img
          className="relative z-20 inline-block h-6 w-6 rounded-full ring-2 ring-white"
          src="https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
          alt=""
        />
        <img
          className="relative z-10 inline-block h-6 w-6 rounded-full ring-2 ring-white"
          src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.25&w=256&h=256&q=80"
          alt=""
        />
        <img
          className="relative z-0 inline-block h-6 w-6 rounded-full ring-2 ring-white"
          src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
          alt=""
        />
      </div>

      <div className="isolate flex -space-x-2 overflow-hidden">
        <img
          className="relative z-30 inline-block h-8 w-8 rounded-full ring-2 ring-white"
          src="https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
          alt=""
        />
        <img
          className="relative z-20 inline-block h-8 w-8 rounded-full ring-2 ring-white"
          src="https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
          alt=""
        />
        <img
          className="relative z-10 inline-block h-8 w-8 rounded-full ring-2 ring-white"
          src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.25&w=256&h=256&q=80"
          alt=""
        />
        <img
          className="relative z-0 inline-block h-8 w-8 rounded-full ring-2 ring-white"
          src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
          alt=""
        />
      </div>

      <div className="isolate flex -space-x-2 overflow-hidden">
        <img
          className="relative z-30 inline-block h-10 w-10 rounded-full ring-2 ring-white"
          src="https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
          alt=""
        />
        <img
          className="relative z-20 inline-block h-10 w-10 rounded-full ring-2 ring-white"
          src="https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
          alt=""
        />
        <img
          className="relative z-10 inline-block h-10 w-10 rounded-full ring-2 ring-white"
          src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.25&w=256&h=256&q=80"
          alt=""
        />
        <img
          className="relative z-0 inline-block h-10 w-10 rounded-full ring-2 ring-white"
          src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
          alt=""
        />
      </div>
    </>
  )
}

Let me know if you need anything else

eddiejaoude avatar Jan 03 '23 13:01 eddiejaoude

GMeet or otherwise to speak elaboratively on it? Let me know, I'll make arrangements

Maybe a Discord call, so others could listen and learn?

eddiejaoude avatar Jan 03 '23 13:01 eddiejaoude

Anything works @eddiejaoude.

thebarshablog avatar Jan 03 '23 13:01 thebarshablog

@eddiejaoude That's great news that we can use the Tailwind components! Amazing!

@thebarshablog Yeah sure I would love to so we can organize the work faster!

ThorOnTheRocks avatar Jan 03 '23 13:01 ThorOnTheRocks

Let me know a date and time according to your convenience @ThorOnTheRocks

thebarshablog avatar Jan 03 '23 15:01 thebarshablog

Let me know a date and time according to your convenience @ThorOnTheRocks

I just sent u a DM on Discord so we can speak there and organize how to split this in tasks

ThorOnTheRocks avatar Jan 03 '23 16:01 ThorOnTheRocks

Hey @eddiejaoude Gian and I spoke over this particular issue and we can work on it together. However, there were some other thoughts we had in mind.

  • Introduce a drop-down, tag-like feature to select from common events people are going to. [Thought over this but still would like to put out if just making such a change for just the events will be an enhancement or not]. Otherwise, both Gian and I can work on stacking the avatars. @ThorOnTheRocks any additions? Let us know if you would like to be co-assigned on this. Thanks.

thebarshablog avatar Jan 10 '23 13:01 thebarshablog

  • @ThorOnTheRocks any additions? Let us know if you would like to be co-assigned on this.

Sure! The ideas sound great as we discussed the other day! The only thing is probably this goes beyond the scope of this issue and probably we could open another issue/feature implementation on this other idea perhaps?

ThorOnTheRocks avatar Jan 10 '23 22:01 ThorOnTheRocks

Keeping changes/PRs small would be great 👍 we can keep adding value/improvements

eddiejaoude avatar Jan 11 '23 21:01 eddiejaoude

Keeping changes/PRs small would be great 👍 we can keep adding value/improvements

@eddiejaoude you may assign us on this.

thebarshablog avatar Jan 12 '23 02:01 thebarshablog

Hi @eddiejaoude I'm trying to figure it out how to best tackle this issue but perhaps I need other opinions and would love to get some feedbacks:

So far what I have been trying to do is to create two different data structures: one with unique events and another with the duplicated events where we keep all the usernames linked.

My only doubt with this approach is that we can get to a pretty crazy level of deep nesting and iteration data. I'm not sure that this will be easy to maintain and scale in the future perhaps:

function removeDuplicateEvents(categorisedEvents) {
    const uniqueEvents = {};
    const seenUrls = new Set();

    ["all", "virtual", "inPerson", "cfpOpen"].forEach(category => {
      uniqueEvents[category] = categorisedEvents[category].filter(event => {
        if (seenUrls.has(event.url)) {
          return false;
        }
        seenUrls.add(event.url);
        return true;
      });
    });
    return uniqueEvents;
  }

  const uniqueEvents = removeDuplicateEvents(categorisedEvents);

  function findDuplicatedEventsByUrl(data) {
    const events = {};
    data.all.forEach(event => {
      if (!events[event.url]) {
        events[event.url] = {
          usernames: [event.username],
          event
        };
      } else {
        events[event.url].usernames.push(event.username);
      }
    });
    const duplicatedEvents = Object.values(events).filter(event => event.usernames.length > 1);
    const result = [];
    duplicatedEvents.forEach((duplicatedEvent) => {
      const { event, usernames } = duplicatedEvent;
      result.push({ event, usernames });
    });
    return result;
  }

  const groupedDuplicatedEvents = findDuplicatedEventsByUrl(categorisedEvents);

I'm not sure if we have to create different components for the grouped events because like this even the data structure is different and won't work with the actual EventCard. I'm kind of stuck now but I'm wondering if this would be the best approach or perhaps we should rethink about the whole issue and change implementation? Probably having a separate Event model where user can create events and the others can join?

Or maybe I'm just overcomplicating my life and we can think a much easier approach.

ThorOnTheRocks avatar Jan 19 '23 23:01 ThorOnTheRocks

I was thinking about using a reduce, something like this ...

Data before...

[
  {
    isVirtual: false,
    isInPerson: true,
    color: 'red',
    name: 'Hack This Fall 3.0',
    description: 'A 36-hour in-person hackathon taking place at Karnavati University in Gandhinagar, Gujarat from February 3rd to 5th, 2023.',
    date: {
      start: '2023-02-03T16:00:00.000-05:00',
      end: '2023-02-05T17:00:00.000-05:00'
    },
    url: 'https://lu.ma/hackthisfall',
    username: 'Aadarsh805'
  },
  {
    isInPerson: true,
    color: 'red',
    name: 'CIVO Navigate',
    description: 'A two-day conference in **Tampa, FL**, revolving around topics such as **Kubernetes**, **Edge Computing**, **Machine Learning**, **Dev/GitOps**, **Observability**, **Security**, and **Cloud Native Transformation**, where I will be delivering a workshop on Open Source developer tool **Acorn**.',
    date: {
      start: '2023-02-07T08:30:00.000-05:00',
      end: '2023-02-08T17:40:00.000-05:00'
    },
    url: 'https://civo.com/navigate',
    username: 'juliafmorgado'
  },
  {
    isVirtual: false,
    isInPerson: true,
    color: 'blue',
    name: 'CIVO Navigate',
    description: 'A two-day conference in **Tampa, FL**, revolving around topics such as **Kubernetes**, **Edge Computing**, **Machine Learning**, **Dev/GitOps**, **Observability**, **Security**, and **Cloud Native Transformation**, where I will be delivering a workshop on Open Source developer tool **Acorn**.',
    date: {
      start: '2023-02-07T08:30:00.000-05:00',
      end: '2023-02-08T17:40:00.000-05:00'
    },
    url: 'https://civo.com/navigate',
    username: 'mocdaniel'
  }
  // ...
]

Example code...

const dedupEvents = eventsFiltered.reduce((acc, obj) => {
    const key = obj["url"];
    const curGroup = acc[key] ?? [];

    return { ...acc, [key]: [...curGroup, obj] };
  }, {});

Data after...

{
  'https://lu.ma/hackthisfall': [
    {
      isVirtual: false,
      isInPerson: true,
      color: 'red',
      name: 'Hack This Fall 3.0',
      description: 'A 36-hour in-person hackathon taking place at Karnavati University in Gandhinagar, Gujarat from February 3rd to 5th, 2023.',
      date: [Object],
      url: 'https://lu.ma/hackthisfall',
      username: 'Aadarsh805'
    }
  ],
  'https://civo.com/navigate': [
    {
      isInPerson: true,
      color: 'red',
      name: 'CIVO Navigate',
      description: 'A two-day conference in **Tampa, FL**, revolving around topics such as **Kubernetes**, **Edge Computing**, **Machine Learning**, **Dev/GitOps**, **Observability**, **Security**, and **Cloud Native Transformation**, where I will be delivering a workshop on Open Source developer tool **Acorn**.',
      date: [Object],
      url: 'https://civo.com/navigate',
      username: 'juliafmorgado'
    },
    {
      isVirtual: false,
      isInPerson: true,
      color: 'blue',
      name: 'CIVO Navigate',
      description: 'A two-day conference in **Tampa, FL**, revolving around topics such as **Kubernetes**, **Edge Computing**, **Machine Learning**, **Dev/GitOps**, **Observability**, **Security**, and **Cloud Native Transformation**, where I will be delivering a workshop on Open Source developer tool **Acorn**.',
      date: [Object],
      url: 'https://civo.com/navigate',
      username: 'mocdaniel'
    }
  ],
  'https://www.harvardwecode.com/': [
    {
      isVirtual: true,
      isInPerson: true,
      color: 'red',
      name: 'Harvard WECODE Conference 2023',
      description: 'The Harvard WECode (Women Engineers Code) Conference is organized by undergraduate women at Harvard University and is an initiative of Harvard Undergraduate Women in CS. WECode hosts the largest student-run women in tech conference in the world. ',
      date: [Object],
      url: 'https://www.harvardwecode.com/',
      username: 'thebarshablog'
    }
  ],
  // ...
}

eddiejaoude avatar Jan 19 '23 23:01 eddiejaoude

Ok that's definitely would be a much cleaner approach. Do you think we do not need a new EventCard component for the stacked avatar or perhaps we can just extend the one we have already? Like when there are more users render the stacked avatar...

ThorOnTheRocks avatar Jan 20 '23 08:01 ThorOnTheRocks

I think we can use the same EventCard and just enhance it to support stacked avatars 👍

eddiejaoude avatar Jan 20 '23 08:01 eddiejaoude

@ThorOnTheRocks you're doing good work, buddy! I'll return on Feb 15 and join you on this. Academic Commitments. Incase of anything issue I notice during these days, will report here.

thebarshablog avatar Jan 20 '23 10:01 thebarshablog

@ThorOnTheRocks I'm finally back after exams. Let me know what you need assistance with.

thebarshablog avatar Feb 17 '23 14:02 thebarshablog

There has been no activity for quite some time so I will be unassigning this Issue.

SaraJaoude avatar Apr 13 '23 04:04 SaraJaoude

Would I be able to pick up this issue? :)

nicwithdev avatar Apr 20 '23 12:04 nicwithdev

Sure thing @nicwithdev , thank you! I will assign it to you now, any questions let us know

eddiejaoude avatar Apr 20 '23 13:04 eddiejaoude

How is it going @nicwithdev ? Any questions let us know

Also please be aware that soon we are going to be merging in a PR that inserts the json files into the Mongo database, so this can be solved 2 ways

  • with a js reduce as mentioned further up in this issue with the current code in main
  • but I think a better and more long term solution would be looking at the PR https://github.com/EddieHubCommunity/LinkFree/pull/5765 that has moved the app to using Mongo and trying to group the events together using the Mongo query which would be more efficient

eddiejaoude avatar May 06 '23 07:05 eddiejaoude

Hey @eddiejaoude I think I should be unassigned so someone else can pick it up. I haven't made any progress.

nicwithdev avatar May 06 '23 23:05 nicwithdev

Ok no problem @nicwithdev , thanks for letting me know. Also let me know if you would like another issue assigned

eddiejaoude avatar May 06 '23 23:05 eddiejaoude

We also have filters

let categorizedEvents = {
    all: events,
    virtual: events.filter((event) => event.isVirtual === true),
    inPerson: events.filter((event) => event.isInPerson === true),
    cfpOpen: events.filter((event) =>
      event.date.cfpClose ? new Date(event.date.cfpClose) > new Date() : false
    ),
    free: events.filter((event) => event.price?.startingFrom === 0),
    paid: events.filter((event) => event.price?.startingFrom > 0),
  };

I was thinking of creating a new object from categorized events and have a users property with array of usernames which could be passed and removing the duplicates

ChinmayMhatre avatar May 24 '23 07:05 ChinmayMhatre