Changeset 5af32f0 for pages/dashboard


Ignore:
Timestamp:
12/29/25 01:16:09 (6 months ago)
Author:
Mihail <mihail2.naumov@…>
Branches:
main
Children:
915ce0f
Parents:
8a7f936
Message:

Added styling to admin dashboard functions and highest ranking popup

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pages/dashboard/admin/+Page.tsx

    r8a7f936 r5af32f0  
    1 import React, { useEffect, useState } from 'react';
     1import React, {useEffect, useState} from 'react';
    22import {
    33    Container, Grid, Paper, Typography, Box, Avatar, Divider, Button,
     
    2525    const [selectedBuildId, setSelectedBuildId] = useState<number | null>(null);
    2626
    27     const [suggestionDialog, setSuggestionDialog] = useState<{ open: boolean, id: number | null, action: 'approved' | 'rejected' }>({ open: false, id: null, action: 'approved' });
     27    // Build approval dialog state
     28    const [buildApprovalDialog, setBuildApprovalDialog] = useState<{
     29        open: boolean,
     30        buildId: number | null,
     31        buildName: string
     32    }>({open: false, buildId: null, buildName: ''});
     33    const [rejectReason, setRejectReason] = useState('');
     34    const [approvalLoading, setApprovalLoading] = useState(false);
     35
     36    const [suggestionDialog, setSuggestionDialog] = useState<{
     37        open: boolean,
     38        id: number | null,
     39        action: 'approved' | 'rejected'
     40    }>({open: false, id: null, action: 'approved'});
    2841    const [adminComment, setAdminComment] = useState("");
    2942
    3043    const loadData = () => {
    3144        getAdminInfoAndData()
    32             .then(res => { setData(res); setLoading(false); })
     45            .then(res => {
     46                setData(res);
     47                setLoading(false);
     48            })
    3349            .catch(err => {
    3450                console.error(err);
     
    3753    };
    3854
    39     useEffect(() => { loadData(); }, []);
    40 
    41     const handleBuildReview = async (buildId: number, isApproved: boolean) => {
    42         if (!confirm(`Are you sure you want to ${isApproved ? 'APPROVE' : 'REJECT'} this build?`)) return;
     55    useEffect(() => {
     56        loadData();
     57    }, []);
     58
     59    const openBuildApproval = (buildId: number, buildName: string) => {
     60        setBuildApprovalDialog({open: true, buildId, buildName});
     61        setRejectReason('');
     62    };
     63
     64    const handleApproveBuild = async () => {
     65        if (!buildApprovalDialog.buildId) return;
     66        setApprovalLoading(true);
    4367        try {
    44             await onSetBuildApprovalStatus({ buildId, isApproved });
     68            await onSetBuildApprovalStatus({buildId: buildApprovalDialog.buildId, isApproved: true});
     69            setBuildApprovalDialog({open: false, buildId: null, buildName: ''});
    4570            loadData();
    46         } catch (e) { alert("Action failed"); }
     71        } catch (e) {
     72            alert("Approve failed");
     73        } finally {
     74            setApprovalLoading(false);
     75        }
     76    };
     77
     78    const handleRejectBuild = async () => {
     79        if (!buildApprovalDialog.buildId || !rejectReason.trim()) return;
     80        setApprovalLoading(true);
     81        try {
     82            await onSetBuildApprovalStatus({buildId: buildApprovalDialog.buildId, isApproved: false});
     83            setBuildApprovalDialog({open: false, buildId: null, buildName: ''});
     84            loadData();
     85        } catch (e) {
     86            alert("Reject failed");
     87        } finally {
     88            setApprovalLoading(false);
     89        }
    4790    };
    4891
    4992    const openSuggestionReview = (id: number, action: 'approved' | 'rejected') => {
    50         setSuggestionDialog({ open: true, id, action });
     93        setSuggestionDialog({open: true, id, action});
    5194        setAdminComment(action === 'approved' ? "" : "");
    5295    };
     
    60103                adminComment: adminComment
    61104            });
    62             // console.error("Test za admincomment: ", adminComment);
    63             setSuggestionDialog({ ...suggestionDialog, open: false });
     105            setSuggestionDialog({...suggestionDialog, open: false});
    64106            loadData();
    65         } catch (e) { alert("Failed to update suggestion"); }
    66     };
    67 
    68     if (loading) return <Box sx={{ p: 5, textAlign: 'center' }}><CircularProgress /></Box>;
    69     if (!data) return <Box sx={{ p: 5, textAlign: 'center' }}>Access Denied</Box>;
     107        } catch (e) {
     108            alert("Failed to update suggestion");
     109        }
     110    };
     111
     112    if (loading) return <Box sx={{p: 5, textAlign: 'center'}}><CircularProgress/></Box>;
     113    if (!data) return <Box sx={{p: 5, textAlign: 'center'}}>Access Denied</Box>;
    70114
    71115    return (
    72         <Container maxWidth="xl" sx={{ mt: 4, mb: 10 }}>
     116        <Container maxWidth="xl" sx={{mt: 4, mb: 10}}>
    73117            <Grid container spacing={4}>
    74118                <Grid item xs={12} md={3}>
    75                     <Paper elevation={3} sx={{ p: 4, display: 'flex', flexDirection: 'column', alignItems: 'center', height: '100%', bgcolor: '#1e1e1e', color: 'white' }}>
    76                         <Avatar sx={{ width: 120, height: 120, mb: 2, bgcolor: 'error.main' }}>
    77                             <AdminPanelSettingsIcon sx={{ fontSize: 70 }} />
     119                    <Paper elevation={3} sx={{
     120                        p: 4,
     121                        display: 'flex',
     122                        flexDirection: 'column',
     123                        alignItems: 'center',
     124                        height: '100%',
     125                        bgcolor: '#1e1e1e',
     126                        color: 'white'
     127                    }}>
     128                        <Avatar sx={{width: 120, height: 120, mb: 2, bgcolor: 'error.main'}}>
     129                            <AdminPanelSettingsIcon sx={{fontSize: 70}}/>
    78130                        </Avatar>
    79131                        <Typography variant="h5" fontWeight="bold">{data.admin.username}</Typography>
    80                         <Typography variant="body2" sx={{ opacity: 0.7, mb: 3 }}>{data.admin.email}</Typography>
    81 
    82                         <Chip label="ADMINISTRATOR" color="error" variant="outlined" sx={{ fontWeight: 'bold' }} />
    83                         <Divider sx={{ width: '100%', my: 3, bgcolor: 'rgba(255,255,255,0.1)' }} />
    84 
    85                         <Box sx={{ width: '100%', textAlign: 'center' }}>
     132                        <Typography variant="body2" sx={{opacity: 0.7, mb: 3}}>{data.admin.email}</Typography>
     133
     134                        <Chip label="ADMINISTRATOR" color="error" variant="outlined" sx={{fontWeight: 'bold'}}/>
     135                        <Divider sx={{width: '100%', my: 3, bgcolor: 'rgba(255,255,255,0.1)'}}/>
     136
     137                        <Box sx={{width: '100%', textAlign: 'center'}}>
    86138                            <Typography variant="h3" fontWeight="bold" color="primary.main">
    87139                                {data.pendingBuilds?.length || 0}
     
    95147                    <Grid container spacing={4} direction="column">
    96148                        <Grid item xs={12}>
    97                             <Paper sx={{ p: 3, borderLeft: '6px solid #9c27b0' }}>
    98                                 <Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
    99                                     <MemoryIcon color="secondary" sx={{ mr: 1 }} />
     149                            <Paper sx={{p: 3, borderLeft: '6px solid #9c27b0'}}>
     150                                <Box sx={{display: 'flex', alignItems: 'center', mb: 2}}>
     151                                    <MemoryIcon color="secondary" sx={{mr: 1}}/>
    100152                                    <Typography variant="h6" fontWeight="bold">
    101153                                        Suggested Components ({data.componentSuggestions?.length || 0})
     
    118170                                            {data.componentSuggestions.map((sug: any) => (
    119171                                                <TableRow key={sug.id}>
    120                                                     <TableCell sx={{ maxWidth: 300 }}>
    121                                                         <a href={sug.link} title={sug.link} style={{textDecoration: 'none', color: 'inherit'}}>
     172                                                    <TableCell sx={{maxWidth: 300}}>
     173                                                        <a href={sug.link} title={sug.link}
     174                                                           style={{textDecoration: 'none', color: 'inherit'}}>
    122175                                                            {sug.description || sug.link}
    123176                                                        </a>
     
    126179                                                    <TableCell>{sug.userId}</TableCell>
    127180                                                    <TableCell align="right">
    128                                                         <IconButton size="small" color="success" onClick={() => openSuggestionReview(sug.id, 'approved')}>
    129                                                             <CheckCircleIcon />
     181                                                        <IconButton size="small" color="success"
     182                                                                    onClick={() => openSuggestionReview(sug.id, 'approved')}>
     183                                                            <CheckCircleIcon/>
    130184                                                        </IconButton>
    131                                                         <IconButton size="small" color="error" onClick={() => openSuggestionReview(sug.id, 'rejected')}>
    132                                                             <CancelIcon />
     185                                                        <IconButton size="small" color="error"
     186                                                                    onClick={() => openSuggestionReview(sug.id, 'rejected')}>
     187                                                            <CancelIcon/>
    133188                                                        </IconButton>
    134189                                                    </TableCell>
     
    142197
    143198                        <Grid item xs={12}>
    144                             <Paper sx={{ p: 3, borderLeft: '6px solid #ed6c02', bgcolor: '#121212' }}>
    145                                 <Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
    146                                     <BuildIcon color="warning" sx={{ mr: 1 }} />
     199                            <Paper sx={{p: 3, borderLeft: '6px solid #ed6c02', bgcolor: '#121212'}}>
     200                                <Box sx={{display: 'flex', alignItems: 'center', mb: 2}}>
     201                                    <BuildIcon color="warning" sx={{mr: 1}}/>
    147202                                    <Typography variant="h6" fontWeight="bold">
    148203                                        Builds Waiting for Approval ({data.pendingBuilds?.length || 0})
     
    156211                                        {data.pendingBuilds.map((build: any) => (
    157212                                            <Grid item xs={12} md={4} key={build.id}>
    158                                                 <Box sx={{ position: 'relative' }}>
     213                                                <Box sx={{position: 'relative'}}>
    159214                                                    <BuildCard
    160215                                                        build={build}
     
    162217                                                    />
    163218                                                    <Box sx={{
    164                                                         mt: 1, display: 'flex', gap: 1,
    165                                                         justifyContent: 'center', bgcolor: '#121212', p: 1, borderRadius: 1
     219                                                        mt: 1,
     220                                                        display: 'flex',
     221                                                        gap: 1,
     222                                                        justifyContent: 'center',
     223                                                        bgcolor: '#292929',
     224                                                        p: 1,
     225                                                        borderRadius: 1
    166226                                                    }}>
    167                                                         <Button variant="contained" color="success" size="small" onClick={() => handleBuildReview(build.id, true)}>
    168                                                             Approve
    169                                                         </Button>
    170                                                         <Button variant="contained" color="error" size="small" onClick={() => handleBuildReview(build.id, false)}>
    171                                                             Reject
     227                                                        <Button
     228                                                            variant="contained"
     229                                                            color="warning"
     230                                                            size="small"
     231                                                            startIcon={<BuildIcon/>}
     232                                                            onClick={() => openBuildApproval(build.id, build.name)}
     233                                                        >
     234                                                            Review
    172235                                                        </Button>
    173236                                                    </Box>
     
    181244
    182245                        <Grid item xs={12}>
    183                             <Paper sx={{ p: 3, borderLeft: '6px solid #2e7d32' }}>
     246                            <Paper sx={{p: 3, borderLeft: '6px solid #2e7d32'}}>
    184247                                <Typography variant="h6" fontWeight="bold" gutterBottom>
    185248                                    My Builds / Sandbox
     
    201264                            </Paper>
    202265                        </Grid>
    203 
    204266                    </Grid>
    205267                </Grid>
    206268            </Grid>
    207269
    208             <Dialog open={suggestionDialog.open} onClose={() => setSuggestionDialog({...suggestionDialog, open: false})}>
     270            <Dialog open={suggestionDialog.open}
     271                    onClose={() => setSuggestionDialog({...suggestionDialog, open: false})}>
    209272                <DialogTitle>Review Component Suggestion</DialogTitle>
    210273                <DialogContent>
     
    221284            </Dialog>
    222285
     286            <Dialog open={buildApprovalDialog.open}
     287                    onClose={() => setBuildApprovalDialog({open: false, buildId: null, buildName: ''})}>
     288                <DialogTitle>Review Build</DialogTitle>
     289                <DialogContent>
     290                    <Typography variant="h6" gutterBottom>{buildApprovalDialog.buildName}</Typography>
     291                    <Typography color="text.secondary" sx={{mb: 2}}>
     292                        Build ID: {buildApprovalDialog.buildId}
     293                    </Typography>
     294                    <TextField
     295                        fullWidth
     296                        multiline
     297                        rows={2}
     298                        label="Reject reason (optional)"
     299                        value={rejectReason}
     300                        onChange={(e) => setRejectReason(e.target.value)}
     301                        placeholder="Why reject this build?"
     302                        sx={{mt: 1}}
     303                    />
     304                </DialogContent>
     305                <DialogActions>
     306                    <Button
     307                        onClick={() => setBuildApprovalDialog({open: false, buildId: null, buildName: ''})}
     308                        disabled={approvalLoading}
     309                    >
     310                        Cancel
     311                    </Button>
     312                    <Button
     313                        onClick={handleRejectBuild}
     314                        variant="outlined"
     315                        color="error"
     316                        disabled={approvalLoading || !rejectReason.trim()}
     317                    >
     318                        {approvalLoading ? <CircularProgress size={20}/> : 'Reject'}
     319                    </Button>
     320                    <Button
     321                        onClick={handleApproveBuild}
     322                        variant="contained"
     323                        color="success"
     324                        disabled={approvalLoading}
     325                    >
     326                        {approvalLoading ? <CircularProgress size={20}/> : 'Approve'}
     327                    </Button>
     328                </DialogActions>
     329            </Dialog>
     330
    223331            <BuildDetailsDialog
    224332                open={!!selectedBuildId}
Note: See TracChangeset for help on using the changeset viewer.