Submitter stuff
This commit is contained in:
@@ -1,56 +1,8 @@
|
||||
import { Paper, Grid, Typography, Box } from "@mui/material";
|
||||
import { Paper, Grid, Typography } from "@mui/material";
|
||||
import { ReviewItemHeader } from "./ReviewItemHeader";
|
||||
import { CopyableField } from "@/app/_components/review/CopyableField";
|
||||
import { SubmissionInfo } from "@/app/ts/Submission";
|
||||
import { MapfixInfo } from "@/app/ts/Mapfix";
|
||||
import { useState, useEffect } from "react";
|
||||
import Link from "next/link";
|
||||
import LaunchIcon from '@mui/icons-material/Launch'; // Import the icon
|
||||
|
||||
// New component to fetch and display submitter info
|
||||
function SubmitterInfo({ submitterId }: { submitterId: string | number }) {
|
||||
const [name, setName] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (!submitterId) return;
|
||||
|
||||
const fetchUserName = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
// Use the internal proxy API route
|
||||
const response = await fetch(`/proxy/users/${submitterId}`);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch user');
|
||||
}
|
||||
const data = await response.json();
|
||||
setName(`@${data.name}`);
|
||||
} catch (error) {
|
||||
console.error("Error fetching user name:", error);
|
||||
setName(String(submitterId)); // Fallback to ID on error
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchUserName();
|
||||
}, [submitterId]);
|
||||
|
||||
if (loading) {
|
||||
return <Typography variant="body1">Loading...</Typography>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Link href={`https://www.roblox.com/users/${submitterId}/profile`} target="_blank" rel="noopener noreferrer" style={{ textDecoration: 'none', color: 'inherit' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, '&:hover': { textDecoration: 'underline' } }}>
|
||||
<Typography>
|
||||
{name || submitterId}
|
||||
</Typography>
|
||||
<LaunchIcon sx={{ fontSize: '1rem', color: 'text.secondary' }} />
|
||||
</Box>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
// Define a field configuration for specific types
|
||||
interface FieldConfig {
|
||||
@@ -82,14 +34,12 @@ export function ReviewItem({
|
||||
if (isSubmission) {
|
||||
// Fields for Submission
|
||||
fields = [
|
||||
{ key: 'Submitter', label: 'Submitter' },
|
||||
{ key: 'AssetID', label: 'Asset ID' },
|
||||
{ key: 'UploadedAssetID', label: 'Uploaded Asset ID' },
|
||||
];
|
||||
} else if (isMapfix) {
|
||||
// Fields for Mapfix
|
||||
fields = [
|
||||
{ key: 'Submitter', label: 'Submitter' },
|
||||
{ key: 'AssetID', label: 'Asset ID' },
|
||||
{ key: 'TargetAssetID', label: 'Target Asset ID' },
|
||||
];
|
||||
@@ -108,16 +58,6 @@ export function ReviewItem({
|
||||
<Grid container spacing={2} sx={{ mt: 2 }}>
|
||||
{fields.map((field) => {
|
||||
const fieldValue = (item as never)[field.key];
|
||||
|
||||
if (field.key === 'Submitter') {
|
||||
return (
|
||||
<Grid item xs={12} sm={6} key={field.key}>
|
||||
<Typography variant="subtitle2" color="text.secondary">{field.label}</Typography>
|
||||
<SubmitterInfo submitterId={fieldValue} />
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
const displayValue = fieldValue === 0 || fieldValue == null ? 'N/A' : fieldValue;
|
||||
const isAssetId = field.key.includes('AssetID') && fieldValue !== 0 && fieldValue != null;
|
||||
|
||||
|
||||
@@ -3,19 +3,52 @@ import { StatusChip } from "@/app/_components/statusChip";
|
||||
import { SubmissionStatus } from "@/app/ts/Submission";
|
||||
import { MapfixStatus } from "@/app/ts/Mapfix";
|
||||
import {Status, StatusMatches} from "@/app/ts/Status";
|
||||
import { useState, useEffect } from "react";
|
||||
import Link from "next/link";
|
||||
import LaunchIcon from '@mui/icons-material/Launch';
|
||||
|
||||
type StatusIdType = SubmissionStatus | MapfixStatus;
|
||||
function SubmitterName({ submitterId }: { submitterId: number }) {
|
||||
const [name, setName] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (!submitterId) return;
|
||||
const fetchUserName = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await fetch(`/proxy/users/${submitterId}`);
|
||||
if (!response.ok) throw new Error('Failed to fetch user');
|
||||
const data = await response.json();
|
||||
setName(`@${data.name}`);
|
||||
} catch {
|
||||
setName(String(submitterId));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
fetchUserName();
|
||||
}, [submitterId]);
|
||||
|
||||
if (loading) return <Typography variant="body1">Loading...</Typography>;
|
||||
return <Link href={`https://www.roblox.com/users/${submitterId}/profile`} target="_blank" rel="noopener noreferrer" style={{ textDecoration: 'none', color: 'inherit' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, '&:hover': { textDecoration: 'underline' } }}>
|
||||
<Typography>
|
||||
{name || submitterId}
|
||||
</Typography>
|
||||
<LaunchIcon sx={{ fontSize: '1rem', color: 'text.secondary' }} />
|
||||
</Box>
|
||||
</Link>
|
||||
}
|
||||
|
||||
interface ReviewItemHeaderProps {
|
||||
displayName: string;
|
||||
statusId: StatusIdType;
|
||||
statusId: SubmissionStatus | MapfixStatus;
|
||||
creator: string | null | undefined;
|
||||
submitterId: number;
|
||||
}
|
||||
|
||||
export const ReviewItemHeader = ({ displayName, statusId, creator }: ReviewItemHeaderProps) => {
|
||||
export const ReviewItemHeader = ({ displayName, statusId, creator, submitterId }: ReviewItemHeaderProps) => {
|
||||
const isProcessing = StatusMatches(statusId, [Status.Validating, Status.Uploading, Status.Submitting]);
|
||||
|
||||
const pulse = keyframes`
|
||||
0%, 100% { opacity: 0.2; transform: scale(0.8); }
|
||||
50% { opacity: 1; transform: scale(1); }
|
||||
@@ -25,7 +58,7 @@ export const ReviewItemHeader = ({ displayName, statusId, creator }: ReviewItemH
|
||||
<>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
||||
<Typography variant="h4" component="h1" gutterBottom>
|
||||
{displayName}
|
||||
{displayName} by {creator}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
{isProcessing && (
|
||||
@@ -60,9 +93,7 @@ export const ReviewItemHeader = ({ displayName, statusId, creator }: ReviewItemH
|
||||
src={`/thumbnails/user/${submitterId}`}
|
||||
sx={{ mr: 1, width: 24, height: 24 }}
|
||||
/>
|
||||
<Typography variant="body1">
|
||||
by {creator || "Unknown Creator"}
|
||||
</Typography>
|
||||
<SubmitterName submitterId={submitterId} />
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user