Skip to content

Commit 91ccfea

Browse files
committed
Multi file owner albums, added some album frontend
1 parent f13a2a2 commit 91ccfea

40 files changed

Lines changed: 1770 additions & 373 deletions

frontend/assets/icons/edit.svg

Lines changed: 1 addition & 0 deletions
Loading

frontend/client/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export type { LoginRedirectUrl } from './models/LoginRedirectUrl';
2323
export type { MessageResponse } from './models/MessageResponse';
2424
export { OAuthProvider } from './models/OAuthProvider';
2525
export type { OAuthProviders } from './models/OAuthProviders';
26+
export type { Page_AlbumData } from './models/Page_AlbumData';
2627
export type { Page_ApplicationData } from './models/Page_ApplicationData';
2728
export type { Page_RegistrationKeyData } from './models/Page_RegistrationKeyData';
2829
export type { Page_UploadData } from './models/Page_UploadData';
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* istanbul ignore file */
2+
/* tslint:disable */
3+
4+
export type Page_AlbumData = {
5+
items: Array<{
6+
/**
7+
* Date of album creation
8+
*/
9+
created: string;
10+
/**
11+
* Optional album description
12+
*/
13+
description?: string | null;
14+
id: string;
15+
name: string;
16+
/**
17+
* Is the album public.
18+
*/
19+
public: boolean;
20+
/**
21+
* User who created the album.
22+
*/
23+
userId: string;
24+
}>;
25+
page: number;
26+
pages: number;
27+
};
28+

frontend/client/models/Page_UploadData.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
export type Page_UploadData = {
55
items: Array<{
6-
albumId?: string | null;
76
hash: string;
87
id: string;
98
name: string;

frontend/client/models/UploadData.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
/* tslint:disable */
33

44
export type UploadData = {
5-
albumId?: string | null;
65
hash: string;
76
id: string;
87
name: string;

frontend/client/services/AlbumService.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { AlbumCreate } from '../models/AlbumCreate';
44
import type { AlbumData } from '../models/AlbumData';
55
import type { AlbumUpdate } from '../models/AlbumUpdate';
66
import type { MessageResponse } from '../models/MessageResponse';
7-
import type { Page_ApplicationData } from '../models/Page_ApplicationData';
7+
import type { Page_AlbumData } from '../models/Page_AlbumData';
88

99
import type { CancelablePromise } from '../core/CancelablePromise';
1010
import type { BaseHttpRequest } from '../core/BaseHttpRequest';
@@ -95,18 +95,41 @@ export class AlbumService {
9595
});
9696
}
9797

98+
/**
99+
* - Allow unverified users: `false`
100+
* - Application token allowed: `true`
101+
* @param albumId
102+
* @param requestBody
103+
* @returns MessageResponse
104+
* @throws ApiError
105+
*/
106+
public addUploads(
107+
albumId: string,
108+
requestBody: Array<string>,
109+
): CancelablePromise<MessageResponse> {
110+
return this.httpRequest.request({
111+
method: 'POST',
112+
url: '/api/album/{album_id}/uploads',
113+
path: {
114+
'album_id': albumId,
115+
},
116+
body: requestBody,
117+
mediaType: 'application/json',
118+
});
119+
}
120+
98121
/**
99122
* - Allow unverified users: `true`
100123
* - Application token allowed: `true`
101124
* @param pageNumber Page to get albums by (starts at 1)
102125
* @param userId
103-
* @returns Page_ApplicationData
126+
* @returns Page_AlbumData
104127
* @throws ApiError
105128
*/
106129
public list(
107130
pageNumber: number,
108131
userId: string,
109-
): CancelablePromise<Page_ApplicationData> {
132+
): CancelablePromise<Page_AlbumData> {
110133
return this.httpRequest.request({
111134
method: 'GET',
112135
url: '/api/user/{user_id}/album/{page_number}',

frontend/client/services/UploadService.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,23 @@ export class UploadService {
2020
* - Allow unverified users: `false`
2121
* - Application token allowed: `true`
2222
* @param formData
23+
* @param albumId Which album will this upload into.
24+
* @param _public Is the file public?
2325
* @returns UploadData
2426
* @throws ApiError
2527
*/
2628
public upload(
2729
formData: UploadFile,
30+
albumId?: string | null,
31+
_public?: boolean | null,
2832
): CancelablePromise<UploadData> {
2933
return this.httpRequest.request({
3034
method: 'POST',
3135
url: '/api/upload',
36+
query: {
37+
'album_id': albumId,
38+
'public': _public,
39+
},
3240
formData: formData,
3341
mediaType: 'multipart/form-data',
3442
errors: {
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import {
2+
Box,
3+
Button,
4+
Flex,
5+
Heading,
6+
Text,
7+
Tooltip,
8+
useColorModeValue,
9+
Icon,
10+
Badge,
11+
VStack,
12+
useDisclosure,
13+
HStack,
14+
Menu,
15+
MenuButton,
16+
MenuList,
17+
MenuItem,
18+
IconButton
19+
} from "@chakra-ui/react"
20+
import { dateToString } from "helpers/util"
21+
import * as React from "react"
22+
import DeleteIcon from "assets/icons/trash.svg"
23+
import EditIcon from "assets/icons/edit.svg"
24+
import FolderIcon from "assets/icons/folder.svg"
25+
import MoreIcon from "assets/icons/more-vertical.svg"
26+
import { AlbumData } from "@/client"
27+
import AlbumModal, { AlbumFormData } from "./AlbumModal"
28+
29+
const AlbumCard: React.FC<{
30+
album: AlbumData,
31+
onOpen: (album: AlbumData) => void,
32+
onDelete: (album: AlbumData) => void,
33+
onUpdate?: (album: AlbumData, updates: AlbumFormData) => void
34+
}> = ({ album, onOpen, onDelete, onUpdate }) => {
35+
const { isOpen, onOpen: openModal, onClose: closeModal } = useDisclosure()
36+
37+
const handleEdit = (e: React.MouseEvent) => {
38+
e.stopPropagation()
39+
openModal()
40+
}
41+
42+
const handleDelete = (e: React.MouseEvent) => {
43+
e.stopPropagation()
44+
onDelete(album)
45+
}
46+
47+
const handleUpdateSubmit = async (formData: AlbumFormData) => {
48+
if (!onUpdate) return
49+
50+
try {
51+
await onUpdate(album, formData)
52+
closeModal()
53+
} catch (error) {
54+
throw error
55+
}
56+
}
57+
58+
59+
const cardBg = useColorModeValue("white", "gray.700")
60+
const borderColor = useColorModeValue("gray.200", "gray.600")
61+
const textColor = useColorModeValue("gray.800", "white")
62+
const subtextColor = useColorModeValue("gray.600", "gray.300")
63+
const mutedTextColor = useColorModeValue("gray.500", "gray.400")
64+
65+
return (
66+
<>
67+
<Box
68+
bg={cardBg}
69+
rounded="lg"
70+
boxShadow="lg"
71+
position="relative"
72+
cursor="pointer"
73+
onClick={() => onOpen(album)}
74+
w={{ sm: "100%", md: "300px" }}
75+
minH="200px"
76+
p={5}
77+
>
78+
{/* Action Menu */}
79+
<Menu>
80+
<MenuButton
81+
as={IconButton}
82+
icon={<Icon as={MoreIcon} w={4} h={4} />}
83+
variant="ghost"
84+
size="sm"
85+
position="absolute"
86+
top={4}
87+
right={4}
88+
onClick={(e) => e.stopPropagation()}
89+
/>
90+
<MenuList>
91+
{onUpdate && (
92+
<MenuItem icon={<Icon as={EditIcon} w={4} h={4} />} onClick={handleEdit}>
93+
Edit Album
94+
</MenuItem>
95+
)}
96+
<MenuItem
97+
icon={<Icon as={DeleteIcon} w={4} h={4} />}
98+
onClick={handleDelete}
99+
color="red.500"
100+
>
101+
Delete Album
102+
</MenuItem>
103+
</MenuList>
104+
</Menu>
105+
106+
<VStack spacing={4} h="full" justify="space-between" align="stretch">
107+
{/* Header with icon and title */}
108+
<VStack spacing={3} align="center">
109+
<Box p={3}>
110+
<Icon
111+
as={FolderIcon}
112+
w={10}
113+
h={10}
114+
color="primary.300"
115+
/>
116+
</Box>
117+
118+
<VStack spacing={1} align="center">
119+
<Heading
120+
fontSize="lg"
121+
fontWeight="semibold"
122+
textAlign="center"
123+
noOfLines={2}
124+
color={textColor}
125+
lineHeight="1.3"
126+
>
127+
{album.name}
128+
</Heading>
129+
130+
{album.description && (
131+
<Text
132+
fontSize="sm"
133+
color={subtextColor}
134+
textAlign="center"
135+
noOfLines={2}
136+
>
137+
{album.description}
138+
</Text>
139+
)}
140+
</VStack>
141+
</VStack>
142+
143+
{/* Footer */}
144+
<VStack spacing={2}>
145+
<HStack justify="space-between" w="full">
146+
<Text fontSize="xs" color={mutedTextColor}>
147+
{dateToString(new Date(album.created))}
148+
</Text>
149+
<Badge
150+
colorScheme={album.public ? "green" : "gray"}
151+
variant="subtle"
152+
fontSize="xs"
153+
px={2}
154+
py={1}
155+
rounded="md"
156+
>
157+
{album.public ? "Public" : "Private"}
158+
</Badge>
159+
</HStack>
160+
</VStack>
161+
</VStack>
162+
</Box>
163+
164+
{onUpdate && (
165+
<AlbumModal
166+
isOpen={isOpen}
167+
onClose={closeModal}
168+
album={album}
169+
onSubmit={handleUpdateSubmit}
170+
/>
171+
)}
172+
</>
173+
)
174+
}
175+
176+
export default AlbumCard

0 commit comments

Comments
 (0)