Skip to content

Commit

Permalink
Merge pull request #23 from like-minded-nus/staging
Browse files Browse the repository at this point in the history
merge staging into main
  • Loading branch information
GayChin authored Apr 23, 2024
2 parents ffcf027 + b62c221 commit 325f1da
Show file tree
Hide file tree
Showing 46 changed files with 1,715 additions and 471 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/prod-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ jobs:
run: sudo docker rm -f like-minded-fe-prod-container || true
- name: Run Docker Container
run: sudo docker run -d -p 3001:3000 --name like-minded-fe-prod-container ${{ secrets.DOCKER_USERNAME }}/like-minded-fe-prod:latest
- name: Remove Unused Docker Images
run: sudo docker image prune -f
2 changes: 2 additions & 0 deletions .github/workflows/staging-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ jobs:
run: sudo docker rm -f like-minded-fe-staging-container || true
- name: Run Docker Container
run: sudo docker run -d -p 3000:3000 --name like-minded-fe-staging-container ${{ secrets.DOCKER_USERNAME }}/like-minded-fe-staging:latest
- name: Remove Unused Docker Images
run: sudo docker image prune -f
3 changes: 3 additions & 0 deletions app/admin/admin-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ const AdminPage = async () => {
if (session?.user.userRole !== 1) {
redirect('/home');
}
if (session?.user.userRole === 1) {
redirect('/admin/user_management');
}

return (
<>
Expand Down
9 changes: 9 additions & 0 deletions app/admin/user_management/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import AdminBase from '../../components/admin-base';
import UsersTable from './users-table';

const Reports = () => {
const component = <UsersTable />;
return <AdminBase content={component} />;
};

export default Reports;
55 changes: 55 additions & 0 deletions app/admin/user_management/reports/bans/bans-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use client';

import { useAppDispatch, useAppSelector } from '@/redux/hooks';
import React, { useEffect } from 'react';
import { Ban } from '@/models/ban';
import { getBannedUsers } from '@/redux/features/banSlice';

const BanTable = () => {
const dispatch = useAppDispatch();
const controller = new AbortController();

// Redux store
const bans: Ban[] = useAppSelector((state) => state.banReducer.bans);

useEffect(() => {
dispatch(getBannedUsers({ controller }));

return () => {
controller.abort();
};
}, []);

useEffect(() => {
console.log(bans);
}, [bans]);

return (
<>
<div className='mt-4'>
<table className='admin-table'>
<thead>
<tr>
<th scope='col'>Ban ID</th>
<th scope='col'>User ID</th>
<th scope='col'>Username</th>
<th scope='col'>Reason</th>
</tr>
</thead>
<tbody>
{bans.map((ban: Ban) => (
<tr key={ban.banId}>
<th scope='row'>{ban.banId}</th>
<td>{ban.userId}</td>
<td>{ban.username}</td>
<td>{ban.bannedReason}</td>
</tr>
))}
</tbody>
</table>
</div>
</>
);
};

export default BanTable;
9 changes: 9 additions & 0 deletions app/admin/user_management/reports/bans/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import AdminBase from '../../../../components/admin-base';
import BanTable from './bans-table';

const Reports = () => {
const component = <BanTable />;
return <AdminBase content={component} />;
};

export default Reports;
9 changes: 9 additions & 0 deletions app/admin/user_management/reports/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import AdminBase from '../../../components/admin-base';
import ReportTable from './report-table';

const Reports = () => {
const component = <ReportTable />;
return <AdminBase content={component} />;
};

export default Reports;
108 changes: 108 additions & 0 deletions app/admin/user_management/reports/report-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
'use client';

import { useAppDispatch, useAppSelector } from '@/redux/hooks';
import React, { useEffect } from 'react';
import { Report } from '@/models/report';
import { getReportedRecords } from '@/redux/features/reportSlice';
import axios from 'axios';
import { useRouter } from 'next/navigation';

const ReportTable = () => {
const endpoint = process.env.NEXT_PUBLIC_API_ENDPOINT ?? '';

const dispatch = useAppDispatch();
const controller = new AbortController();
const { push } = useRouter();

// Redux store
const reports: Report[] = useAppSelector(
(state) => state.reportReducer.reports
);

useEffect(() => {
dispatch(getReportedRecords({ controller }));

return () => {
controller.abort();
};
}, []);

useEffect(() => {
console.log(reports);
}, [reports]);

const handleBanClick = async (id: Number, userId: Number, reason: String) => {
const confirmResponse = window.confirm(
'Are you sure you want to ban this user?'
);
if (confirmResponse) {
const response = await axios.post(`${endpoint}/ban`, {
id: id,
userId: userId,
bannedReason: reason,
});

if (response.data.status === 200) {
push(window.location.pathname + '/bans');
} else {
alert('An error has occured!');
}
} else {
console.log('User cancelled the action.');
}
};

const handleViewBanRecords = () => {
push('/admin/user_management/reports/bans');
};

return (
<>
<div className='mt-4'>
<table className='admin-table'>
<thead>
<tr>
<th scope='col'>Report ID</th>
<th scope='col'>Username</th>
<th scope='col'>Reason</th>
<th scope='col'>Action</th>
</tr>
</thead>
<tbody>
{reports.map((report: Report) => (
<tr key={report.reportId}>
<th scope='row'>{report.reportId}</th>
<td>{report.username}</td>
<td>{report.reportedReason}</td>
<td>
<button
className='btn btn-delete btn-square'
onClick={(e) => {
e.preventDefault();

handleBanClick(
report.reportId,
report.userId,
report.reportedReason
);
}}
>
Ban
</button>
</td>
</tr>
))}
</tbody>
</table>
<button
className='btn btn-primary btn-square float-end mt-4'
onClick={handleViewBanRecords}
>
View Ban Records
</button>
</div>
</>
);
};

export default ReportTable;
8 changes: 8 additions & 0 deletions app/admin/user_management/users-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';
import { redirect } from 'next/navigation';

const UsersTable = async () => {
redirect('/admin/user_management/reports');
};

export default UsersTable;
10 changes: 0 additions & 10 deletions app/admin/vendors/[id]/[voucherId]/page.tsx

This file was deleted.

7 changes: 0 additions & 7 deletions app/admin/vendors/[id]/[voucherId]/view-voucher-page.tsx

This file was deleted.

75 changes: 48 additions & 27 deletions app/admin/vendors/[id]/create_voucher/create-voucher-form.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use client';
import { useState } from 'react';
import { ChangeEvent, useState } from 'react';
import axios from 'axios';
import VoucherDatepicker from '@/app/components/voucher-datepicker';
import { useRouter } from 'next/navigation';
Expand All @@ -9,10 +9,17 @@ const CreateVoucherForm = () => {
const [voucherName, setVoucherName] = useState('');
const [voucherEndDate, setVoucherEndDate] = useState('');
const [voucherDescription, setVoucherDescription] = useState('');
const [voucherType, setVoucherType] = useState<number>(1);
const [redeemStatus, setRedeemStatus] = useState(0);
const [vendorId, setVendorId] = useState('');
const [voucherNameError, setVoucherNameError] = useState('');
const [voucherDescriptionError, setVoucherDescriptionError] = useState('');
const [voucherAmount, setVoucherAmount] = useState<number>(1);

interface VoucherTypes {
voucherType: number;
voucherDesc: string;
}

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
Expand All @@ -35,11 +42,6 @@ const CreateVoucherForm = () => {
return;
}

if (voucherDescription.trim() === '') {
alert('Voucher description cannot be empty.');
return;
}

try {
const endpoint = process.env.NEXT_PUBLIC_API_ENDPOINT ?? '';
if (!endpoint) {
Expand All @@ -48,7 +50,8 @@ const CreateVoucherForm = () => {
const response = await axios.post(`${endpoint}/vouchers/create_voucher`, {
voucherName,
voucherEndDate,
voucherDescription,
voucherType,
voucherAmount,
redeemStatus,
vendorId,
});
Expand All @@ -71,6 +74,11 @@ const CreateVoucherForm = () => {
setVoucherEndDate(selectedDate.toISOString());
};

const handleDropdownChange = (e: ChangeEvent<HTMLSelectElement>) => {
setVoucherType(Number(e.target.value));
console.log('dropdown change to: ' + e.target.value);
};

const getVendorIdFromUrl = () => {
if (typeof window === 'undefined') {
return '';
Expand Down Expand Up @@ -148,30 +156,43 @@ const CreateVoucherForm = () => {
</div>
<div className='mb-4 flex flex-col'>
<label
htmlFor='voucherDescription'
htmlFor='voucherType'
className='mb-2 block text-gray-200'
>
Voucher Type:
</label>
<select
value={voucherType}
onChange={handleDropdownChange}
name='voucherType'
className={`w-full rounded-md border bg-gray-700 px-4 py-2 text-gray-200`}
>
<option value='1' key={1}>
Free Trials
</option>
<option value='2' key={2}>
Percentage Discount
</option>
</select>
</div>

<div className='mb-4 flex flex-col'>
<label
htmlFor='voucherAmount'
className='mb-2 block text-gray-200'
>
Description:
{voucherType === 1
? 'Number of free trials'
: 'Percentage Discount (%)'}
</label>
<input
type='text'
id='voucherDescription'
value={voucherDescription}
onChange={(e) => setVoucherDescription(e.target.value)}
onBlur={() => {
if (voucherDescription.trim() === '') {
setVoucherDescriptionError(
'Voucher description cannot be empty.'
);
} else {
setVoucherDescriptionError('');
}
}}
className={`w-full rounded-md border bg-gray-700 ${
voucherDescriptionError
? 'border-red-500'
: 'border-gray-200'
} px-4 py-2 text-gray-200`}
type='number'
id='voucherType'
value={voucherAmount}
min={1}
max={100}
onChange={(e) => setVoucherAmount(Number(e.target.value))}
className={`w-full rounded-md border bg-gray-700 px-4 py-2 text-gray-200`}
required
/>
{voucherDescriptionError && (
Expand Down
Loading

0 comments on commit 325f1da

Please sign in to comment.