Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable cover image editing for Event Admin #145

Merged
merged 15 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
NEXT_PUBLIC_ACM_API_URL="https://api.acmucsd.com/api/v2"
NEXT_PUBLIC_KLEFKI_API_URL=""
NEXT_PUBLIC_TOTP_KEY=""
NEXT_PUBLIC_TOTP_KEY=""

# Set this environment variable to any string if you're connecting
# to the production API and want to use production file size limits.
# process.env.NEXT_PUBLIC_PRODUCTION
99 changes: 48 additions & 51 deletions src/components/admin/event/EventDetailsForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ const EventDetailsForm = (props: IProps) => {
const [selectedCover, setSelectedCover] = useState<File | null>(null);
const [cover, setCover] = useState<File | null>(null);
const coverUrl = useObjectUrl(cover);
const eventCover = coverUrl || initialValues.cover;

const createEvent: SubmitHandler<FillInLater> = formData => {
if (!cover) {
Expand Down Expand Up @@ -112,7 +113,7 @@ const EventDetailsForm = (props: IProps) => {
onClick: () => router.push(`https://acmucsd.com/events/${event.uuid}`),
},
]);
router.push(config.admin.events.homeRoute);
router.replace(config.admin.events.homeRoute);
},
onFailCallback: error => {
setLoading(false);
Expand All @@ -138,6 +139,7 @@ const EventDetailsForm = (props: IProps) => {
start,
end,
},
cover: cover || undefined,
onSuccessCallback: event => {
setLoading(false);
showToast('Event Details Saved!', '', [
Expand All @@ -146,7 +148,7 @@ const EventDetailsForm = (props: IProps) => {
onClick: () => router.push(`https://acmucsd.com/events/${event.uuid}`),
},
]);
router.push(config.admin.events.homeRoute);
router.replace(config.admin.events.homeRoute);
},
onFailCallback: error => {
setLoading(false);
Expand All @@ -163,7 +165,7 @@ const EventDetailsForm = (props: IProps) => {
token: AUTH_TOKEN,
onSuccessCallback: () => {
setLoading(false);
router.push(config.admin.events.homeRoute);
router.replace(config.admin.events.homeRoute);
},
});
};
Expand Down Expand Up @@ -280,54 +282,49 @@ const EventDetailsForm = (props: IProps) => {
/>
</EventDetailsFormItem>

{/* Only show this in create mode */}
{editing ? null : (
<>
<label htmlFor="cover">Cover Image</label>
<EventDetailsFormItem>
{coverUrl && (
<Image src={coverUrl} alt="Selected cover image" width={480} height={270} />
)}
<input
type="file"
id="cover"
accept="image/*"
onChange={e => {
const file = e.currentTarget.files?.[0];
e.currentTarget.value = '';
if (file) {
setSelectedCover(file);
}
}}
/>
</EventDetailsFormItem>
<Cropper
file={selectedCover}
aspectRatio={1920 / 1080}
maxFileHeight={1080}
maxSize={config.file.MAX_EVENT_COVER_SIZE_KB * 1024}
onCrop={async file => {
setCover(
new File([file], selectedCover?.name ?? 'image', {
type: file.type,
})
);
setSelectedCover(null);
}}
onClose={reason => {
setSelectedCover(null);
if (reason === 'cannot-compress') {
showToast(
'Your image has too much detail and cannot be compressed.',
'Try shrinking your image.'
);
} else if (reason !== null) {
showToast('This image format is not supported.');
}
}}
/>
</>
)}
<label htmlFor="cover">Cover Image</label>
<EventDetailsFormItem>
{eventCover && (
<Image src={eventCover} alt="Selected cover image" width={480} height={270} />
)}
<input
type="file"
id="cover"
accept="image/*"
onChange={e => {
const file = e.currentTarget.files?.[0];
e.currentTarget.value = '';
if (file) {
setSelectedCover(file);
}
}}
/>
</EventDetailsFormItem>
<Cropper
file={selectedCover}
aspectRatio={1920 / 1080}
maxFileHeight={1080}
maxSize={config.file.MAX_EVENT_COVER_SIZE_KB * 1024}
onCrop={async file => {
setCover(
new File([file], selectedCover?.name ?? 'image', {
type: file.type,
})
);
setSelectedCover(null);
}}
onClose={reason => {
setSelectedCover(null);
if (reason === 'cannot-compress') {
showToast(
'Your image has too much detail and cannot be compressed.',
'Try shrinking your image.'
);
} else if (reason !== null) {
showToast('This image format is not supported.');
}
}}
/>
</div>

<div className={style.submitButtons}>
Expand Down
3 changes: 1 addition & 2 deletions src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Cat from '@/public/assets/graphics/cat404.png';

const env = process.env.NODE_ENV;
const isDevelopment = env !== 'production';
const isDevelopment = process.env.NEXT_PUBLIC_PRODUCTION === undefined;

const config = {
api: {
Expand Down
10 changes: 10 additions & 0 deletions src/lib/managers/AdminEventManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,24 @@ export const createNewEvent = async (

interface EditEventRequest {
event: Partial<Event>;
cover?: File;
uuid: UUID;
}

export const editEvent = async (data: EditEventRequest & AuthAPIHandlerProps) => {
const { onSuccessCallback, onFailCallback, token, event, uuid } = data;
if (data.cover && data.cover.size > config.file.MAX_EVENT_COVER_SIZE_KB * 1024) {
onFailCallback?.(new Error('Cover size too large'));
return;
}

try {
const modifiedEvent = await EventAPI.editEvent(token, uuid, event);
if (data.cover) {
// There's some weird behavior that happens when we editEvent after uploading a new
// event image, so I've kept the API calls in the same order as createNewEvent
await EventAPI.uploadEventImage(token, uuid, data.cover);
}

onSuccessCallback?.(modifiedEvent);
} catch (e: any) {
Expand Down