|
1 | 1 | <script lang="ts"> |
2 | | - import { api, type Id } from "@packages/convex"; |
3 | | - import type { Doc } from "@packages/convex/src/convex/_generated/dataModel"; |
| 2 | + import { api, type Doc, type Id } from "@packages/convex"; |
4 | 3 | import { useConvexClient, useQuery } from "convex-svelte"; |
5 | 4 | import FilePreview from "~/features/files/upload/FilePreview.svelte"; |
6 | 5 | import FileSelector from "~/features/files/upload/Selector.svelte"; |
7 | 6 | import { FileUploader } from "~/features/files/upload/uploader.svelte"; |
| 7 | + import Attachment from "~/icons/attachment.svelte"; |
8 | 8 | import MdiClose from "~/icons/mdi-close.svelte"; |
9 | 9 | import { useMutation } from "~/lib/useMutation.svelte.ts"; |
| 10 | +
|
10 | 11 | import EmojiPalette from "./EmojiPalette.svelte"; |
11 | 12 | import VoteMaker from "./VoteMaker.svelte"; |
12 | 13 |
|
|
33 | 34 | const convex = useConvexClient(); |
34 | 35 |
|
35 | 36 | let messageContent = $state(""); |
36 | | - let authorName = $state(""); |
37 | 37 | let showEmojiPalette = $state(false); |
38 | 38 | let showFileSelector = $state(false); |
39 | 39 | let attachedFiles = $state<File[]>([]); |
40 | 40 |
|
| 41 | + const clickable = $derived.by<boolean>(() => { |
| 42 | + // post ongoing |
| 43 | + if (sendMessageMutation.processing) return false; |
| 44 | + // identity not loaded yet |
| 45 | + if (!identity.data) return false; |
| 46 | + // empty content |
| 47 | + if (!messageContent.trim() && attachedFiles.length === 0 && !voteIsValid()) |
| 48 | + return false; |
| 49 | + return true; |
| 50 | + }); |
| 51 | +
|
41 | 52 | let showVoteMaker = $state(false); |
42 | 53 | let vote = $state<Vote>({ |
43 | 54 | title: "", |
44 | 55 | maxVotes: 1, |
45 | 56 | voteOptions: [], |
46 | 57 | voters: [], |
47 | 58 | }); |
48 | | -
|
49 | | - const personalization = useQuery(api.personalization.getPersonalization, { |
50 | | - organizationId: organizationId, |
51 | | - }); |
52 | | -
|
53 | | - $effect(() => { |
54 | | - if (identity?.data && !authorName) { |
55 | | - authorName = |
56 | | - personalization.data?.nickname ?? |
57 | | - identity.data.name ?? |
58 | | - identity.data.email ?? |
59 | | - "匿名"; |
60 | | - } |
61 | | - }); |
| 59 | + function voteIsValid() { |
| 60 | + if (!vote.title.trim()) return false; |
| 61 | + if (vote.voteOptions.length === 0) return false; |
| 62 | + if (vote.maxVotes === 0) return false; |
| 63 | + return true; |
| 64 | + } |
62 | 65 |
|
63 | 66 | const uploader = new FileUploader(() => ({ |
64 | 67 | organizationId, |
65 | 68 | })); |
66 | 69 |
|
67 | 70 | async function sendMessage() { |
68 | | - if (!messageContent.trim() && attachedFiles.length === 0) return; |
| 71 | + if (!clickable) return; |
| 72 | + if (!identity.data) return; |
69 | 73 |
|
70 | 74 | const attachments = (await uploader.uploadAll(attachedFiles)).map( |
71 | 75 | (it) => it.id, |
72 | 76 | ); |
73 | 77 |
|
74 | 78 | let voteId: Id<"votes"> | undefined; |
75 | | - if (vote.title.trim() && vote.voteOptions.length !== 0) { |
| 79 | + if (voteIsValid()) { |
76 | 80 | voteId = await convex.mutation(api.vote.addVote, { |
77 | 81 | title: vote.title, |
78 | 82 | maxVotes: vote.maxVotes, |
|
83 | 87 | await sendMessageMutation.run({ |
84 | 88 | channelId, |
85 | 89 | content: messageContent.trim() || "", |
86 | | - author: authorName.trim() || "匿名", |
| 90 | + author: identity.data.name, |
87 | 91 | parentId: replyingTo?._id ?? undefined, |
88 | 92 | attachments, |
89 | 93 | vote: voteId, |
|
167 | 171 | {#if showVoteMaker} |
168 | 172 | <VoteMaker bind:vote /> |
169 | 173 | {/if} |
170 | | - |
171 | | - <div class="flex gap-2"> |
172 | | - <input |
173 | | - type="text" |
174 | | - placeholder="ユーザー名" |
175 | | - class="input input-sm input-bordered w-32" |
176 | | - bind:value={authorName} |
177 | | - /> |
178 | | - </div> |
| 174 | + <div class="flex gap-2"></div> |
179 | 175 |
|
180 | 176 | <div class="flex gap-2"> |
181 | 177 | <div class="flex-1 space-y-2"> |
|
195 | 191 | title="ファイルを添付" |
196 | 192 | type="button" |
197 | 193 | > |
198 | | - <svg |
199 | | - class="h-4 w-4" |
200 | | - fill="none" |
201 | | - stroke="currentColor" |
202 | | - viewBox="0 0 24 24" |
203 | | - > |
204 | | - <path |
205 | | - stroke-linecap="round" |
206 | | - stroke-linejoin="round" |
207 | | - stroke-width="2" |
208 | | - d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13" |
209 | | - ></path> |
210 | | - </svg> |
| 194 | + <Attachment /> |
211 | 195 | {showFileSelector ? "キャンセル" : "ファイル添付"} |
212 | 196 | </button> |
213 | 197 | <button |
|
224 | 208 | <button |
225 | 209 | class="btn btn-primary self-end" |
226 | 210 | onclick={sendMessage} |
227 | | - disabled={(!messageContent.trim() && attachedFiles.length === 0) || |
228 | | - sendMessageMutation.processing} |
| 211 | + disabled={!clickable} |
229 | 212 | > |
230 | 213 | {#if sendMessageMutation.processing} |
231 | 214 | <span class="loading loading-spinner loading-sm"></span> |
|
0 commit comments