Skip to content

Commit

Permalink
Merge branch 'main' into sean/fulfill
Browse files Browse the repository at this point in the history
  • Loading branch information
SheepTester authored Aug 19, 2024
2 parents a664aea + 964791d commit cd164cb
Show file tree
Hide file tree
Showing 15 changed files with 329 additions and 32 deletions.
63 changes: 61 additions & 2 deletions src/components/admin/event/ManageEventCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { Button } from '@/components/common';
import { GoogleCalendarButton } from '@/components/events/CalendarButtons';
import { config, showToast } from '@/lib';
import { AdminEventManager } from '@/lib/managers';
import { CookieService } from '@/lib/services';
import { PublicEvent } from '@/lib/types/apiResponses';
import { CookieType } from '@/lib/types/enums';
import { reportError } from '@/lib/utils';
import Image from 'next/image';
import Link from 'next/link';
Expand All @@ -17,6 +19,7 @@ interface IProps {
const ManageEventCard = ({ event }: IProps) => {
const router = useRouter();
const [acmurlLoading, setAcmurlLoading] = useState(false);
const [discordEvent, setDiscordEvent] = useState<string | null>(event.discordEvent);

const publicEventLink = `https://acmucsd.com/events/${event.uuid}`;

Expand All @@ -28,7 +31,23 @@ const ManageEventCard = ({ event }: IProps) => {
AdminEventManager.createDiscordEvent({
...event,
image: event.cover,
onSuccessCallback: () => {
onSuccessCallback: data => {
const AUTH_TOKEN = CookieService.getClientCookie(CookieType.ACCESS_TOKEN);
const eventID = data.split(' ').pop();

AdminEventManager.editEvent({
token: AUTH_TOKEN,
uuid: event.uuid,
event: {
...event,
discordEvent: eventID,
},
onFailCallback: error => {
reportError('Unable to edit event', error);
},
});

if (eventID) setDiscordEvent(eventID);
showToast('Successfully created event!', 'Check your server to confirm all details');
},
onFailCallback: e => {
Expand All @@ -37,6 +56,44 @@ const ManageEventCard = ({ event }: IProps) => {
});
};

const updateDiscordEvent = () => {
if (!discordEvent) {
showToast("Couldn't update Discord Event...", `${event.title} doesn't have a Discord Event!`);
return;
}

AdminEventManager.patchDiscordEvent({
...event,
eventID: discordEvent,
image: event.cover,
onSuccessCallback: () => {
showToast('Successfully edited event!', 'Check your server to confirm all details');
},
onFailCallback: e => {
reportError('Error while editing Discord Event!', e);
},
});
};

const deleteDiscordEvent = () => {
if (!discordEvent) {
showToast("Couldn't delete Discord Event...", `${event.title} doesn't have a Discord Event!`);
return;
}

AdminEventManager.deleteDiscordEvent({
...event,
discordEvent,
onSuccessCallback: () => {
setDiscordEvent(null);
showToast('Successfully deleted event!', 'Check your server to confirm deletion');
},
onFailCallback: e => {
reportError('Error while deleting Discord Event!', e);
},
});
};

const generateACMURL = () => {
if (!event.eventLink) {
showToast("Couldn't generate ACMURL...", `${event.title} doesn't have an event link!`);
Expand Down Expand Up @@ -84,7 +141,9 @@ const ManageEventCard = ({ event }: IProps) => {
<a href={publicEventLink}>View Public Event Page</a>
<Link href={`${config.admin.events.editRoute}/${event.uuid}`}>Edit Details</Link>
<Button onClick={duplicateEvent}>Duplicate Event</Button>
<Button onClick={generateDiscordEvent}>Generate Discord Event</Button>
{!discordEvent && <Button onClick={generateDiscordEvent}>Create New Discord Event</Button>}
{discordEvent && <Button onClick={updateDiscordEvent}>Update Discord Event</Button>}
{discordEvent && <Button onClick={deleteDiscordEvent}>Delete Discord Event</Button>}
<Button onClick={generateACMURL} disabled={acmurlLoading}>
Generate ACMURL
</Button>
Expand Down
2 changes: 1 addition & 1 deletion src/components/profile/Preview/style.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
align-items: center;
display: flex;
flex-direction: column;

text-align: center;

.pfp {
Expand Down
34 changes: 34 additions & 0 deletions src/lib/api/AdminAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { config } from '@/lib';
import type { ModifyUserAccessLevelResponse, PrivateProfile } from '@/lib/types/apiResponses';
import axios from 'axios';

/**
* Update current user's access level
* @param token Authorization bearer token
* @param user Email of the user whose access is being updated
* @param accessType The user's updated access type
* @returns The updated user profile
*/
export const manageUserAccess = async (
token: string,
user: string,
accessType: string
): Promise<PrivateProfile[]> => {
const accessUpdates = [{ user: user, accessType: accessType }];

const requestUrl = `${config.api.baseUrl}${config.api.endpoints.admin.access}`;

const response = await axios.patch<ModifyUserAccessLevelResponse>(
requestUrl,
{ accessUpdates: accessUpdates },
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);

return response.data.updatedUsers;
};

export default manageUserAccess;
48 changes: 44 additions & 4 deletions src/lib/api/KlefkiAPI.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { config } from '@/lib';
import { URL } from '@/lib/types';
import { CreateDiscordEventRequest, GenerateACMURLRequest } from '@/lib/types/apiRequests';
import type { NotionEventDetails, NotionEventPreview } from '@/lib/types/apiResponses';
import {
CreateDiscordEventRequest,
DeleteDiscordEventRequest,
GenerateACMURLRequest,
PatchDiscordEventRequest,
} from '@/lib/types/apiRequests';
import type {
KlefkiAPIResponse,
NotionEventDetails,
NotionEventPreview,
} from '@/lib/types/apiResponses';
import axios from 'axios';
import totp from 'totp-generator';

Expand Down Expand Up @@ -34,11 +43,42 @@ export const getNotionEventPage = async (pageUrl: URL): Promise<NotionEventDetai
return response.data;
};

export const createDiscordEvent = async (event: CreateDiscordEventRequest): Promise<void> => {
export const createDiscordEvent = async (
event: CreateDiscordEventRequest
): Promise<KlefkiAPIResponse> => {
const { klefki } = config;
const requestUrl = `${klefki.baseUrl}${klefki.endpoints.discord.event}`;

await axios.post<void>(requestUrl, event, {
const response = await axios.post<KlefkiAPIResponse>(requestUrl, event, {
headers: {
Authorization: `Bearer ${generateToken(klefki.key)}`,
},
});

return response.data;
};

export const patchDiscordEvent = async (
event: PatchDiscordEventRequest
): Promise<KlefkiAPIResponse> => {
const { klefki } = config;
const requestUrl = `${klefki.baseUrl}${klefki.endpoints.discord.event}`;

const response = await axios.patch<KlefkiAPIResponse>(requestUrl, event, {
headers: {
Authorization: `Bearer ${generateToken(klefki.key)}`,
},
});

return response.data;
};

export const deleteDiscordEvent = async (event: DeleteDiscordEventRequest): Promise<void> => {
const { klefki } = config;
const requestUrl = `${klefki.baseUrl}${klefki.endpoints.discord.event}`;

await axios.delete<void>(requestUrl, {
data: event,
headers: {
Authorization: `Bearer ${generateToken(klefki.key)}`,
},
Expand Down
20 changes: 20 additions & 0 deletions src/lib/api/StoreAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,26 @@ export const getFutureOrderPickupEvents = async (
return response.data.pickupEvents;
};

export const getValidFutureOrderPickupEvents = async (
token: string
): Promise<PublicOrderPickupEvent[]> => {
return getFutureOrderPickupEvents(token).then(events =>
events
.filter(event => event.status !== 'CANCELLED')
.filter(
event => !(event.orders && event.orderLimit && event.orders.length > event.orderLimit)
)
// filter out events that have a start time less than 2 days from now
.filter(event => {
const startTime = new Date(event.start);
const now = Date.now();
const twoDaysInMs = 2 * 24 * 60 * 60 * 1000;
const twoDaysFromNow = new Date(now + twoDaysInMs);
return startTime >= twoDaysFromNow;
})
);
};

export const placeMerchOrder = async (
token: string,
data: PlaceMerchOrderRequest
Expand Down
1 change: 1 addition & 0 deletions src/lib/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * as AdminAPI from './AdminAPI';
export * as AuthAPI from './AuthAPI';
export * as EventAPI from './EventAPI';
export * as FeedbackAPI from './FeedbackAPI';
Expand Down
2 changes: 2 additions & 0 deletions src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const config = {
attendance: '/admin/attendance',
bonus: '/admin/bonus',
emails: '/admin/email',
access: '/admin/access',
},
event: {
event: '/event',
Expand Down Expand Up @@ -106,6 +107,7 @@ const config = {
grantPastAttendance: '/admin/attendance',
awardMilestone: '/admin/milestone',
viewResumes: '/admin/resumes',
manageUserAccess: '/admin/access',
store: {
items: '/admin/store/items',
pickup: '/admin/store/pickup',
Expand Down
47 changes: 40 additions & 7 deletions src/lib/managers/AdminEventManager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { EventAPI, KlefkiAPI } from '@/lib/api';
import config from '@/lib/config';
import { CookieService } from '@/lib/services';
import type { APIHandlerProps, AuthAPIHandlerProps, URL, UUID } from '@/lib/types';
import {
CancelPickupEventRequest,
Expand All @@ -11,6 +12,7 @@ import {
Event,
GenerateACMURLRequest,
OrderPickupEvent,
PatchDiscordEventRequest,
UploadEventImageRequest,
} from '@/lib/types/apiRequests';
import type {
Expand All @@ -19,6 +21,7 @@ import type {
PublicOrder,
PublicOrderPickupEvent,
} from '@/lib/types/apiResponses';
import { CookieType } from '@/lib/types/enums';

interface GetEventFromNotion {
pageUrl: URL;
Expand All @@ -44,17 +47,25 @@ export const getEventFromNotionURL = async (
}
};

/**
* Create Discord event
* @param data
*/
export const createDiscordEvent = async (
data: CreateDiscordEventRequest & APIHandlerProps<void>
data: CreateDiscordEventRequest & APIHandlerProps<string>
) => {
const { onSuccessCallback, onFailCallback, ...event } = data;
try {
await KlefkiAPI.createDiscordEvent(event);
onSuccessCallback?.();
const data = await KlefkiAPI.createDiscordEvent(event);
onSuccessCallback?.(data.message);
} catch (e: any) {
onFailCallback?.(e.response.data.error);
}
};

export const patchDiscordEvent = async (
data: PatchDiscordEventRequest & APIHandlerProps<string>
) => {
const { onSuccessCallback, onFailCallback, ...event } = data;
try {
const data = await KlefkiAPI.patchDiscordEvent(event);
onSuccessCallback?.(data.message);
} catch (e: any) {
onFailCallback?.(e.response.data.error);
}
Expand Down Expand Up @@ -116,6 +127,28 @@ export const editEvent = async (data: EditEventRequest & AuthAPIHandlerProps<Pub
}
};

export const deleteDiscordEvent = async (data: PublicEvent & APIHandlerProps<void>) => {
const { onSuccessCallback, onFailCallback, ...event } = data;
try {
if (event.discordEvent) {
await KlefkiAPI.deleteDiscordEvent({
eventID: event.discordEvent,
});
}

const AUTH_TOKEN = CookieService.getClientCookie(CookieType.ACCESS_TOKEN);
await editEvent({
token: AUTH_TOKEN,
uuid: event.uuid,
event: { ...event, discordEvent: null },
});

onSuccessCallback?.();
} catch (e: any) {
onFailCallback?.(e.response.data.error);
}
};

export const createPickupEvent = async (
token: string,
pickupEvent: OrderPickupEvent
Expand Down
20 changes: 20 additions & 0 deletions src/lib/managers/AdminUserManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { AdminAPI } from '@/lib/api';
import { CookieService } from '@/lib/services';
import { APIHandlerProps } from '@/lib/types';
import { UserAccessUpdates } from '@/lib/types/apiRequests';
import { PrivateProfile } from '@/lib/types/apiResponses';
import { CookieType } from '@/lib/types/enums';

const manageUserAccess = async (data: UserAccessUpdates & APIHandlerProps<PrivateProfile[]>) => {
const { user, accessType, onSuccessCallback, onFailCallback } = data;

try {
const token = CookieService.getClientCookie(CookieType.ACCESS_TOKEN);
const updatedUsers = await AdminAPI.manageUserAccess(token, user, accessType);
onSuccessCallback?.(updatedUsers);
} catch (e: any) {
onFailCallback?.(e);
}
};

export default manageUserAccess;
9 changes: 9 additions & 0 deletions src/lib/types/apiRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export interface OptionalEventProperties {
eventLink?: string;
requiresStaff?: boolean;
staffPointBonus?: number;
discordEvent: string | null;
}

export interface Event extends OptionalEventProperties {
Expand Down Expand Up @@ -416,6 +417,14 @@ export interface CreateDiscordEventRequest {
image?: string;
}

export interface PatchDiscordEventRequest extends CreateDiscordEventRequest {
eventID: UUID;
}

export interface DeleteDiscordEventRequest {
eventID: UUID;
}

export interface GenerateACMURLRequest {
shortlink: string;
longlink: string;
Expand Down
Loading

0 comments on commit cd164cb

Please sign in to comment.