Skip to content

Commit

Permalink
#DeckValidation
Browse files Browse the repository at this point in the history
- Cleaned up PR.
  • Loading branch information
CheBato committed Feb 22, 2025
1 parent 070a8e5 commit 8c4e3cd
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 14 deletions.
28 changes: 23 additions & 5 deletions src/app/_components/Lobby/_subcomponents/SetUpCard/SetUpCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,25 @@ const SetUpCard: React.FC<ISetUpProps> = ({
};
const handleOnChangeDeck = async () => {
if (!deckLink || readyStatus) return;
const deckData = deckLink ? await fetchDeckData(deckLink, false) : null;
sendLobbyMessage(['changeDeck', deckData])
try {
const deckData = deckLink ? await fetchDeckData(deckLink, false) : null;
sendLobbyMessage(['changeDeck', deckData])
}catch (error){
setDisplayerror(true);
setDeckErrorDetails(undefined);
if(error instanceof Error){
if(error.message.includes('Forbidden')) {
setDeckErrorSummary('Couldn\'t import, deck. The deck is set to private');
setDeckErrorDetails({
[DeckValidationFailureReason.DeckSetToPrivate]: true,
});
}else{
setDeckErrorSummary('Couldn\'t import, deck is invalid.');
}
}
showInlineErrorTextFor5s(connectedUser.deckErrors);
return;
}
}

const showInlineErrorTextFor5s = (deckErrors:IDeckValidationFailures) =>{
Expand All @@ -69,7 +86,9 @@ const SetUpCard: React.FC<ISetUpProps> = ({

// ------------------ Listen for changes to deckErrors ------------------ //
useEffect(() => {
if (!connectedUser?.deckErrors) {
// get error messages
const deckErrors: IDeckValidationFailures = connectedUser.deckErrors;
if (!deckErrors) {
// No validation errors => clear any old error states
setDeckErrorSummary(null);
setDeckErrorDetails(undefined);
Expand All @@ -78,8 +97,7 @@ const SetUpCard: React.FC<ISetUpProps> = ({
setBlockError(false);
return;
}
// get error messages
const deckErrors: IDeckValidationFailures = connectedUser.deckErrors;

const temporaryErrors: IDeckValidationFailures = connectedUser.importDeckErrors;
// Determine if a blocking error exists (ignoring NotImplemented and temporary errors)
const hasBlockingError = Object.entries(deckErrors).some(([reason, value]) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import { usePathname, useRouter } from 'next/navigation';
import { useUser } from '@/app/_contexts/User.context';
import { fetchDeckData } from '@/app/_utils/fetchDeckData';
import { ErrorModal } from '@/app/_components/_sharedcomponents/Error/ErrorModal';
import { IDeckValidationFailures } from '@/app/_validators/DeckValidation/DeckValidationTypes';
import {
DeckValidationFailureReason,
IDeckValidationFailures
} from '@/app/_validators/DeckValidation/DeckValidationTypes';

interface ICreateGameFormProps {
format?: string | null;
Expand Down Expand Up @@ -70,7 +73,25 @@ const CreateGameForm: React.FC<ICreateGameFormProps> = ({
// Handle Create Game Submission
const handleCreateGameSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
const deckData = deckLink ? await fetchDeckData(deckLink,false) : null;
let deckData = null

try {
deckData = deckLink ? await fetchDeckData(deckLink, false) : null;
}catch (error){
setDeckErrorDetails(undefined);
if(error instanceof Error){
if(error.message.includes('Forbidden')) {
setDeckErrorSummary('Couldn\'t import, deck. The deck is set to private');
setDeckErrorDetails({
[DeckValidationFailureReason.DeckSetToPrivate]: true,
});
}else{
setDeckErrorSummary('Couldn\'t import, deck is invalid.');
}
}
showInlineErrorTextFor5s();
return;
}
try {
const payload = {
user: user || sessionStorage.getItem('anonymousUserId'),
Expand Down
2 changes: 1 addition & 1 deletion src/app/_components/_sharedcomponents/Error/ErrorModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const ErrorModal: React.FC<ErrorModalProps> = ({
<ul style={{ margin: 0, paddingLeft: '1.2rem' }}>
{messages.map((msg, index) => (
<li key={index}>
<Typography variant="body1" sx={{ color: 'white' }}>
<Typography variant="body1" sx={{ color: 'white', pl:'0px' }}>
{msg}
</Typography>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import StyledTextField from '../_styledcomponents/StyledTextField';
import { useRouter } from 'next/navigation';
import { useUser } from '@/app/_contexts/User.context';
import { fetchDeckData } from '@/app/_utils/fetchDeckData';
import { IDeckValidationFailures } from '@/app/_validators/DeckValidation/DeckValidationTypes';
import {
DeckValidationFailureReason,
IDeckValidationFailures
} from '@/app/_validators/DeckValidation/DeckValidationTypes';
import { ErrorModal } from '@/app/_components/_sharedcomponents/Error/ErrorModal';

interface ICreateGameFormProps {
Expand Down Expand Up @@ -51,7 +54,25 @@ const QuickGameForm: React.FC<ICreateGameFormProps> = () => {
const handleJoinGameQueue = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
setQueueState(true);
const deckData = deckLink ? await fetchDeckData(deckLink, false) : null;;
let deckData = null
try {
deckData = deckLink ? await fetchDeckData(deckLink, false) : null;
}catch (error){
setQueueState(false);
setDeckErrorDetails(undefined);
if(error instanceof Error){
if(error.message.includes('Forbidden')) {
setDeckErrorSummary('Couldn\'t import, deck. The deck is set to private');
setDeckErrorDetails({
[DeckValidationFailureReason.DeckSetToPrivate]: true,
});
}else{
setDeckErrorSummary('Couldn\'t import, deck is invalid.');
}
}
showInlineErrorTextFor5s();
return;
}
try {
const payload = {
user: user,
Expand All @@ -71,7 +92,7 @@ const QuickGameForm: React.FC<ICreateGameFormProps> = () => {
if (!response.ok) {
const errors = result.errors || {};
setQueueState(false);
setDeckErrorSummary('Couldn\'t import, deck is invalid or set to private.');
setDeckErrorSummary('Couldn\'t import, deck is invalid.');
setDeckErrorDetails(errors);
showInlineErrorTextFor5s();
return
Expand All @@ -80,7 +101,6 @@ const QuickGameForm: React.FC<ICreateGameFormProps> = () => {
setDeckErrorDetails(undefined);
router.push('/quickGame');
} catch (error) {
console.error(error);
setQueueState(false);
setDeckErrorSummary('Error creating game.');
setDeckErrorDetails(undefined);
Expand Down
2 changes: 1 addition & 1 deletion src/app/_utils/fetchDeckData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ export const fetchDeckData = async (deckLink: string, fetchAll: boolean = true)
} else {
console.error('Unexpected error:', error);
}
return null; // or throw error again
throw error // or throw error again
}
};
2 changes: 2 additions & 0 deletions src/app/_validators/DeckValidation/DeckValidationTypes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export enum DeckValidationFailureReason {
NotImplemented = 'notImplemented',
DeckSetToPrivate = 'deckSetToPrivate',
IllegalInFormat = 'illegalInFormat',
TooManyLeaders = 'tooManyLeaders',
InvalidDeckData = 'invalidDeckData',
Expand All @@ -20,6 +21,7 @@ export interface IDeckValidationFailures {
[DeckValidationFailureReason.IllegalInFormat]?: ICardIdAndName[];
[DeckValidationFailureReason.TooManyLeaders]?: boolean;
[DeckValidationFailureReason.InvalidDeckData]?: boolean;
[DeckValidationFailureReason.DeckSetToPrivate]?: boolean;
[DeckValidationFailureReason.MinDecklistSizeNotMet]?: {
minDecklistSize: number;
actualDecklistSize: number;
Expand Down
3 changes: 3 additions & 0 deletions src/app/_validators/DeckValidation/getReadableDeckErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export function getReadableDeckErrors(
if (failures[DeckValidationFailureReason.TooManyLeaders]) {
messages.push(`There are too many Leaders for ${format}.`);
}
if(failures[DeckValidationFailureReason.DeckSetToPrivate]) {
messages.push('The deck is set to private. Change the deck to unlisted on swudb.')
}

// Object-like errors (MinDecklistSizeNotMet, etc.)
if (failures[DeckValidationFailureReason.MinDecklistSizeNotMet]) {
Expand Down
5 changes: 4 additions & 1 deletion src/app/api/swudbdeck/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ export async function GET(req: Request) {
const apiUrl = `https://swudb.com/api/getDeckJson/${deckId}`;

response = await fetch(apiUrl, { method: 'GET' });

if (!response.ok) {
if(response.status === 403) {
return NextResponse.json({ error: 'Deck is set to Private. Change deck to unlisted on swudb' }, { status: 403 });
}
console.error('SWUDB API error:', response.statusText);
throw new Error(`SWUDB API error: ${response.statusText}`);
}
Expand All @@ -69,6 +71,7 @@ export async function GET(req: Request) {

return NextResponse.json(data);
} catch (error) {
console.log(error);
if (error instanceof Error) {
console.error('Internal Server Error:', error.message);
return NextResponse.json({ error: error.message }, { status: 500 });
Expand Down

0 comments on commit 8c4e3cd

Please sign in to comment.