enzostvs HF staff commited on
Commit
e8410db
β€’
1 Parent(s): eb29a95

emoji reaction

Browse files
prisma/dev.db CHANGED
Binary files a/prisma/dev.db and b/prisma/dev.db differ
 
src/lib/components/community/Card.svelte CHANGED
@@ -1,5 +1,4 @@
1
  <script lang="ts">
2
- import Add from "$lib/components/community/reactions/Add.svelte";
3
  import type { CommunityCard } from "$lib/type";
4
  import Reactions from "./reactions/Reactions.svelte";
5
 
@@ -17,9 +16,6 @@
17
  <p class="text-white/75 font-regular text-sm">{card.model.id}</p>
18
  </div>
19
  <div class="flex items-center justify-start gap-2">
20
- {#if card.reactions.length > 0}
21
- <Reactions reactions={card.reactions} />
22
- {/if}
23
- <Add count={card?.reactions?.length} />
24
  </div>
25
  </div>
 
1
  <script lang="ts">
 
2
  import type { CommunityCard } from "$lib/type";
3
  import Reactions from "./reactions/Reactions.svelte";
4
 
 
16
  <p class="text-white/75 font-regular text-sm">{card.model.id}</p>
17
  </div>
18
  <div class="flex items-center justify-start gap-2">
19
+ <Reactions reactions={card.reactions} gallery_id={card.id} />
 
 
 
20
  </div>
21
  </div>
src/lib/components/community/reactions/Add.svelte CHANGED
@@ -4,6 +4,9 @@
4
  import { REACTION_EMOJIS } from "$lib/utils";
5
 
6
  export let count: number;
 
 
 
7
 
8
  let isOpen: boolean = false;
9
  $: uuid = Math.random().toString(36).substring(7);
@@ -20,6 +23,24 @@
20
  if (browser) {
21
  window.addEventListener("click", handleClick);
22
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  </script>
24
 
25
  <div
@@ -27,6 +48,7 @@
27
  class="rounded-full text-sm text-white/80 hover:text-white font-bold flex items-center justify-start gap-1.5 px-1.5 py-1 border border-dashed border-white/80 hover:border-white relative z-[2]"
28
  class:!border-white={isOpen}
29
  class:!text-white={isOpen}
 
30
  >
31
  <button on:click={() => isOpen = !isOpen}>
32
  <Icon icon="fluent:emoji-add-16-regular" class="w-5 h-5" />
@@ -36,8 +58,13 @@
36
  class:opacity-100={isOpen}
37
  class:pointer-events-auto={isOpen}
38
  >
39
- {#each REACTION_EMOJIS as emoji}
40
- <div class="w-8 h-8 hover:bg-neutral-200 rounded-full text-center flex items-center justify-center">{emoji}</div>
 
 
 
 
 
41
  {/each}
42
  </div>
43
  </div>
 
4
  import { REACTION_EMOJIS } from "$lib/utils";
5
 
6
  export let count: number;
7
+ export let reactions: Array<{ emoji: string, count: number }> = [];
8
+ export let gallery_id: string;
9
+ export let onAdd: (emoji: string, id: string) => void;
10
 
11
  let isOpen: boolean = false;
12
  $: uuid = Math.random().toString(36).substring(7);
 
23
  if (browser) {
24
  window.addEventListener("click", handleClick);
25
  }
26
+
27
+ const handleReaction = async (emoji: string) => {
28
+ await fetch(`/api/community/reaction`, {
29
+ method: "POST",
30
+ body: JSON.stringify({ emoji, gallery_id }),
31
+ headers: {
32
+ "Content-Type": "application/json",
33
+ },
34
+ })
35
+ .then(res => res.json())
36
+ .then(data => {
37
+ if (!data.delete) {
38
+ onAdd(emoji, data.id)
39
+ }
40
+ })
41
+ }
42
+
43
+ $: AVAILABLE_EMOJIS = REACTION_EMOJIS.filter(e => !reactions.find(emj => emj.emoji === e));
44
  </script>
45
 
46
  <div
 
48
  class="rounded-full text-sm text-white/80 hover:text-white font-bold flex items-center justify-start gap-1.5 px-1.5 py-1 border border-dashed border-white/80 hover:border-white relative z-[2]"
49
  class:!border-white={isOpen}
50
  class:!text-white={isOpen}
51
+ class:opacity-0={count >= 4}
52
  >
53
  <button on:click={() => isOpen = !isOpen}>
54
  <Icon icon="fluent:emoji-add-16-regular" class="w-5 h-5" />
 
58
  class:opacity-100={isOpen}
59
  class:pointer-events-auto={isOpen}
60
  >
61
+ {#each AVAILABLE_EMOJIS as emoji}
62
+ <button
63
+ class="w-8 h-8 hover:bg-neutral-200 rounded-full text-center flex items-center justify-center"
64
+ on:click={() => handleReaction(emoji)}
65
+ >
66
+ {emoji}
67
+ </button>
68
  {/each}
69
  </div>
70
  </div>
src/lib/components/community/reactions/Reaction.svelte CHANGED
@@ -1,9 +1,28 @@
1
  <script lang="ts">
2
  export let emoji: string;
3
  export let count: number;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  </script>
5
 
6
- <div class="rounded-full bg-white text-sm text-neutral-800 font-bold flex items-center justify-start gap-1.5 px-2.5 py-1 border border-white">
 
 
 
7
  <span>{emoji}</span>
8
  {count}
9
- </div>
 
1
  <script lang="ts">
2
  export let emoji: string;
3
  export let count: number;
4
+ export let gallery_id: string;
5
+ export let onReact: (emoji: string, id: string, deleted: boolean) => void;
6
+
7
+ const handleReaction = async (emoji: string) => {
8
+ await fetch(`/api/community/reaction`, {
9
+ method: "POST",
10
+ body: JSON.stringify({ emoji, gallery_id }),
11
+ headers: {
12
+ "Content-Type": "application/json",
13
+ },
14
+ })
15
+ .then(res => res.json())
16
+ .then(data => {
17
+ onReact(emoji, data.id, data.delete);
18
+ })
19
+ }
20
  </script>
21
 
22
+ <button
23
+ class="rounded-full bg-white text-sm text-neutral-800 font-bold flex items-center justify-start gap-1.5 px-2.5 py-1 border border-white hover:bg-neutral-200"
24
+ on:click={() => handleReaction(emoji)}
25
+ >
26
  <span>{emoji}</span>
27
  {count}
28
+ </button>
src/lib/components/community/reactions/Reactions.svelte CHANGED
@@ -1,8 +1,14 @@
1
  <script lang="ts">
2
  import type { ReactionType } from "$lib/type";
 
3
  import Reaction from "$lib/components/community/reactions/Reaction.svelte";
 
 
 
 
4
 
5
  export let reactions: ReactionType[] = [];
 
6
 
7
  const groupReactionsByEmoji = (reactions: ReactionType[]) => {
8
  const grouped = new Set(reactions.map((reaction) => reaction.emoji));
@@ -14,9 +20,28 @@
14
  });
15
  };
16
 
17
- const groupedReactions = groupReactionsByEmoji(reactions);
18
  </script>
19
 
20
  {#each groupedReactions as reaction}
21
- <Reaction emoji={reaction.emoji} count={reaction?.count} />
22
- {/each}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <script lang="ts">
2
  import type { ReactionType } from "$lib/type";
3
+ import Add from "$lib/components/community/reactions/Add.svelte";
4
  import Reaction from "$lib/components/community/reactions/Reaction.svelte";
5
+ import { get } from 'svelte/store';
6
+ import { userStore } from "$lib/stores/use-user";
7
+
8
+ let user = get(userStore);
9
 
10
  export let reactions: ReactionType[] = [];
11
+ export let gallery_id: string;
12
 
13
  const groupReactionsByEmoji = (reactions: ReactionType[]) => {
14
  const grouped = new Set(reactions.map((reaction) => reaction.emoji));
 
20
  });
21
  };
22
 
23
+ $: groupedReactions = groupReactionsByEmoji(reactions);
24
  </script>
25
 
26
  {#each groupedReactions as reaction}
27
+ <Reaction
28
+ emoji={reaction.emoji}
29
+ count={reaction?.count}
30
+ {gallery_id}
31
+ onReact={(emoji, id, deleted) => {
32
+ if (deleted) {
33
+ reactions = reactions.filter((reaction) => reaction.id !== id);
34
+ } else {
35
+ reactions = [...reactions, { emoji, hf_user_id: user?.sub, galleryId: gallery_id, id }];
36
+ }
37
+ }}
38
+ />
39
+ {/each}
40
+ <Add
41
+ count={groupedReactions?.length}
42
+ reactions={groupedReactions}
43
+ {gallery_id}
44
+ onAdd={(emoji, id) => {
45
+ reactions = [...reactions, { emoji, hf_user_id: user?.sub, galleryId: gallery_id, id }];
46
+ }}
47
+ />
src/lib/utils/index.ts CHANGED
@@ -53,5 +53,5 @@ export const tokenIsAvailable = async (token: string) => {
53
  })
54
 
55
  const user = await userRequest.clone().json().catch(() => ({}));
56
- return !!user?.sub
57
  }
 
53
  })
54
 
55
  const user = await userRequest.clone().json().catch(() => ({}));
56
+ return user?.sub ? user : null;
57
  }
src/routes/+layout.svelte CHANGED
@@ -4,7 +4,7 @@
4
  import { userStore } from "$lib/stores/use-user";
5
 
6
  export let data;
7
- userStore.set(data.user);
8
  </script>
9
 
10
  <div class="flex items-start">
 
4
  import { userStore } from "$lib/stores/use-user";
5
 
6
  export let data;
7
+ userStore.set(data?.user?.user);
8
  </script>
9
 
10
  <div class="flex items-start">
src/routes/api/community/reaction/+server.ts ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { json, type RequestEvent } from '@sveltejs/kit';
2
+ import { tokenIsAvailable } from '$lib/utils';
3
+ import { REACTION_EMOJIS } from "$lib/utils";
4
+ import prisma from '$lib/prisma';
5
+
6
+ /** @type {import('./$types').RequestHandler} */
7
+
8
+ export async function POST({ cookies, request } : RequestEvent) {
9
+ const token = cookies.get('hf_access_token')
10
+ if (!token) {
11
+ return json({
12
+ error: {
13
+ token: "You must be logged"
14
+ }
15
+ }, { status: 401 })
16
+ }
17
+
18
+ const is_token_available = await tokenIsAvailable(token)
19
+ if (!is_token_available) {
20
+ return json({
21
+ error: {
22
+ token: "Invalid token"
23
+ }
24
+ }, { status: 401 })
25
+ }
26
+
27
+ const { emoji, gallery_id } = await request.json()
28
+
29
+ if (!REACTION_EMOJIS.includes(emoji)) {
30
+ return json({
31
+ error: {
32
+ emoji: "Invalid emoji"
33
+ }
34
+ }, { status: 400 })
35
+ }
36
+
37
+ if (!gallery_id ) {
38
+ return json({
39
+ error: {
40
+ gallery_id: "Invalid gallery_id"
41
+ }
42
+ }, { status: 400 })
43
+ }
44
+
45
+ const gallery = await prisma.gallery.findUnique({
46
+ where: {
47
+ id: gallery_id
48
+ }
49
+ })
50
+
51
+ if (!gallery) {
52
+ return json({
53
+ error: {
54
+ gallery_id: "Gallery not found"
55
+ }
56
+ }, { status: 404 })
57
+ }
58
+
59
+ const reaction_exist = await prisma.reaction.findFirst({
60
+ where: {
61
+ galleryId: gallery_id,
62
+ hf_user_id: is_token_available.sub,
63
+ emoji
64
+ }
65
+ })
66
+
67
+ if (reaction_exist) {
68
+ await prisma.reaction.delete({
69
+ where: {
70
+ id: reaction_exist.id
71
+ }
72
+ })
73
+
74
+ return json({
75
+ success: true,
76
+ delete: true,
77
+ id: reaction_exist.id
78
+ })
79
+ }
80
+
81
+ const new_reaction = await prisma.reaction.create({
82
+ data: {
83
+ emoji,
84
+ galleryId: gallery_id,
85
+ hf_user_id: is_token_available.sub
86
+ }
87
+ })
88
+
89
+ return json({
90
+ success: true,
91
+ delete: false,
92
+ id: new_reaction.id
93
+ })
94
+ }