Skip to content
Merged
20 changes: 11 additions & 9 deletions apps/web/actions/organization/upload-space-icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
import { db } from "@cap/database";
import { getCurrentUser } from "@cap/database/auth/session";
import { spaces } from "@cap/database/schema";
import { serverEnv } from "@cap/env";
import { S3Buckets } from "@cap/web-backend";
import type { Space } from "@cap/web-domain";
import { ImageUpload, type Space } from "@cap/web-domain";
import { eq } from "drizzle-orm";
import { Effect, Option } from "effect";
import { revalidatePath } from "next/cache";
Expand Down Expand Up @@ -54,9 +53,11 @@ export async function uploadSpaceIcon(

// Prepare new file key
const fileExtension = file.name.split(".").pop();
const fileKey = `organizations/${
space.organizationId
}/spaces/${spaceId}/icon-${Date.now()}.${fileExtension}`;
const fileKey = ImageUpload.ImageKey.make(
`organizations/${
space.organizationId
}/spaces/${spaceId}/icon-${Date.now()}.${fileExtension}`,
);

const [bucket] = await S3Buckets.getBucketAccess(Option.none()).pipe(
runPromise,
Expand Down Expand Up @@ -89,12 +90,13 @@ export async function uploadSpaceIcon(
)
.pipe(runPromise);

const iconUrl = fileKey;

await db().update(spaces).set({ iconUrl }).where(eq(spaces.id, spaceId));
await db()
.update(spaces)
.set({ iconUrl: fileKey })
.where(eq(spaces.id, spaceId));

revalidatePath("/dashboard");
return { success: true, iconUrl };
return { success: true, iconUrl: fileKey };
} catch (error) {
console.error("Error uploading space icon:", error);
throw new Error(error instanceof Error ? error.message : "Upload failed");
Expand Down
19 changes: 10 additions & 9 deletions apps/web/app/(org)/dashboard/caps/Caps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@

import type { VideoMetadata } from "@cap/database/types";
import { Button } from "@cap/ui";
import type { Video } from "@cap/web-domain";
import type { ImageUpload, Video } from "@cap/web-domain";
import { faFolderPlus, faInfoCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Effect, Exit } from "effect";
import { useRouter, useSearchParams } from "next/navigation";
import { useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { useEffectMutation } from "@/lib/EffectRuntime";
import { useEffectMutation, useRpcClient } from "@/lib/EffectRuntime";
import { useVideosAnalyticsQuery } from "@/lib/Queries/Analytics";
import { AnalyticsRequest } from "@/lib/Requests/AnalyticsRequest";
import { Rpc, withRpc } from "@/lib/Rpcs";
import { useDashboardContext } from "../Contexts";
import {
NewFolderDialog,
Expand All @@ -36,11 +34,14 @@ export type VideoData = {
totalComments: number;
totalReactions: number;
foldersData: FolderDataType[];
sharedOrganizations: { id: string; name: string; iconUrl?: string }[];
sharedOrganizations: {
id: string;
name: string;
iconUrl?: ImageUpload.ImageUrl | null;
}[];
sharedSpaces?: {
id: string;
name: string;
iconUrl: string;
isOrg: boolean;
organizationId: string;
}[];
Expand Down Expand Up @@ -147,12 +148,12 @@ export const Caps = ({
});
};

const rpc = useRpcClient();

const { mutate: deleteCaps, isPending: isDeletingCaps } = useEffectMutation({
mutationFn: Effect.fn(function* (ids: Video.VideoId[]) {
if (ids.length === 0) return;

const rpc = yield* Rpc;

const fiber = yield* Effect.gen(function* () {
const results = yield* Effect.all(
ids.map((id) => rpc.VideoDelete(id).pipe(Effect.exit)),
Expand Down Expand Up @@ -203,7 +204,7 @@ export const Caps = ({
});

const { mutate: deleteCap, isPending: isDeletingCap } = useEffectMutation({
mutationFn: (id: Video.VideoId) => withRpc((r) => r.VideoDelete(id)),
mutationFn: (id: Video.VideoId) => rpc.VideoDelete(id),
onSuccess: () => {
toast.success("Cap deleted successfully");
router.refresh();
Expand Down
13 changes: 7 additions & 6 deletions apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@cap/ui";
import type { Video } from "@cap/web-domain";
import type { ImageUpload, Video } from "@cap/web-domain";
import { HttpClient } from "@effect/platform";
import {
faCheck,
Expand Down Expand Up @@ -41,7 +41,7 @@ import {
type ImageLoadingStatus,
VideoThumbnail,
} from "@/components/VideoThumbnail";
import { useEffectMutation } from "@/lib/EffectRuntime";
import { useEffectMutation, useRpcClient } from "@/lib/EffectRuntime";
import { withRpc } from "@/lib/Rpcs";
import { usePublicEnv } from "@/utils/public-env";
import { PasswordDialog } from "../PasswordDialog";
Expand All @@ -63,12 +63,12 @@ export interface CapCardProps extends PropsWithChildren {
sharedOrganizations?: {
id: string;
name: string;
iconUrl?: string | null;
iconUrl?: ImageUpload.ImageUrl | null;
}[];
sharedSpaces?: {
id: string;
name: string;
iconUrl?: string | null;
iconUrl?: ImageUpload.ImageUrl | null;
organizationId: string;
}[];
ownerName: string | null;
Expand Down Expand Up @@ -133,11 +133,12 @@ export const CapCard = ({
const [confirmOpen, setConfirmOpen] = useState(false);

const router = useRouter();
const rpc = useRpcClient();

const downloadMutation = useEffectMutation({
mutationFn: () =>
Effect.gen(function* () {
const result = yield* withRpc((r) => r.VideoGetDownloadInfo(cap.id));
const result = yield* rpc.VideoGetDownloadInfo(cap.id);
const httpClient = yield* HttpClient.HttpClient;
if (Option.isSome(result)) {
const fetchResponse = yield* httpClient.get(result.value.downloadUrl);
Expand Down Expand Up @@ -175,7 +176,7 @@ export const CapCard = ({
});

const duplicateMutation = useEffectMutation({
mutationFn: () => withRpc((r) => r.VideoDuplicate(cap.id)),
mutationFn: () => rpc.VideoDuplicate(cap.id),
onSuccess: () => {
router.refresh();
},
Expand Down
10 changes: 5 additions & 5 deletions apps/web/app/(org)/dashboard/caps/components/Folder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import { useRouter } from "next/navigation";
import { useEffect, useRef, useState } from "react";
import { toast } from "sonner";
import { moveVideoToFolder } from "@/actions/folders/moveVideoToFolder";
import { useEffectMutation } from "@/lib/EffectRuntime";
import { withRpc } from "@/lib/Rpcs";
import { useEffectMutation, useRpcClient } from "@/lib/EffectRuntime";
import { ConfirmationDialog } from "../../_components/ConfirmationDialog";
import { useDashboardContext, useTheme } from "../../Contexts";
import { registerDropTarget } from "../../folder/[id]/components/ClientCapCard";
Expand Down Expand Up @@ -70,8 +69,10 @@ const FolderCard = ({
}),
});

const rpc = useRpcClient();

const deleteFolder = useEffectMutation({
mutationFn: (id: Folder.FolderId) => withRpc((r) => r.FolderDelete(id)),
mutationFn: (id: Folder.FolderId) => rpc.FolderDelete(id),
onSuccess: () => {
router.refresh();
toast.success("Folder deleted successfully");
Expand All @@ -83,8 +84,7 @@ const FolderCard = ({
});

const updateFolder = useEffectMutation({
mutationFn: (data: Folder.FolderUpdate) =>
withRpc((r) => r.FolderUpdate(data)),
mutationFn: (data: Folder.FolderUpdate) => rpc.FolderUpdate(data),
onSuccess: () => {
toast.success("Folder name updated successfully");
router.refresh();
Expand Down
19 changes: 9 additions & 10 deletions apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ import { Option } from "effect";
import { useRouter } from "next/navigation";
import React, { useEffect, useRef, useState } from "react";
import { toast } from "sonner";
import { useEffectMutation } from "@/lib/EffectRuntime";
import { withRpc } from "@/lib/Rpcs";
import { useEffectMutation, useRpcClient } from "@/lib/EffectRuntime";
import {
BlueFolder,
type FolderHandle,
Expand Down Expand Up @@ -101,16 +100,16 @@ export const NewFolderDialog: React.FC<Props> = ({
),
);

const rpc = useRpcClient();

const createFolder = useEffectMutation({
mutationFn: (data: { name: string; color: Folder.FolderColor }) =>
withRpc((r) =>
r.FolderCreate({
name: data.name,
color: data.color,
spaceId: Option.fromNullable(spaceId),
parentId: Option.none(),
}),
),
rpc.FolderCreate({
name: data.name,
color: data.color,
spaceId: Option.fromNullable(spaceId),
parentId: Option.none(),
}),
onSuccess: () => {
setFolderName("");
setSelectedColor(null);
Expand Down
Loading