EddieHubCommunity / BioDrop

Connect to your audience with a single link. Showcase the content you create and your projects in one place. Make it easier for people to find, follow and subscribe.
https://biodrop.io
MIT License
5.73k stars 3.96k forks source link

[FEATURE] Group events together #2600

Closed eddiejaoude closed 1 year ago

eddiejaoude commented 1 year ago

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

github-actions[bot] commented 1 year ago

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.

ThorOnTheRocks commented 1 year ago

@eddiejaoude Can I get this one?

eddiejaoude commented 1 year ago

Sure, assigned to you 👍

eddiejaoude commented 1 year ago

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

thebarshablog commented 1 year ago

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!

ThorOnTheRocks commented 1 year ago

@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!

thebarshablog commented 1 year ago

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

eddiejaoude commented 1 year ago

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 commented 1 year ago

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?

thebarshablog commented 1 year ago

Anything works @eddiejaoude.

ThorOnTheRocks commented 1 year ago

@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!

thebarshablog commented 1 year ago

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

ThorOnTheRocks commented 1 year ago

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

thebarshablog commented 1 year ago

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.

ThorOnTheRocks commented 1 year ago
  • @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?

eddiejaoude commented 1 year ago

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

thebarshablog commented 1 year ago

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

@eddiejaoude you may assign us on this.

ThorOnTheRocks commented 1 year ago

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.

eddiejaoude commented 1 year ago

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'
    }
  ],
  // ...
}
ThorOnTheRocks commented 1 year ago

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...

eddiejaoude commented 1 year ago

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

thebarshablog commented 1 year ago

@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 commented 1 year ago

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

SaraJaoude commented 1 year ago

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

nicwithdev commented 1 year ago

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

eddiejaoude commented 1 year ago

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

eddiejaoude commented 1 year ago

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

nicwithdev commented 1 year ago

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

eddiejaoude commented 1 year ago

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

ChinmayMhatre commented 1 year ago

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