Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:ita-social-projects/Forum into #…
Browse files Browse the repository at this point in the history
…682_improvingTheMaskForEnteringA_PhoneNumberInTheContact_Tab
  • Loading branch information
ohorodnykostap committed Jul 15, 2024
2 parents aab1b2e + 11e0347 commit 7d99307
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 5 deletions.
27 changes: 27 additions & 0 deletions BackEnd/profiles/migrations/0018_profile_status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 4.2.3 on 2024-07-05 11:48

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("profiles", "0017_remove_profile_banner_image_and_more"),
]

operations = [
migrations.AddField(
model_name="profile",
name="status",
field=models.CharField(
choices=[
("undefined", "Undefined"),
("pending", "Pending Moderation"),
("blocked", "Blocked"),
("approved", "Approved"),
("auto_approved", "Auto Approved"),
],
default="undefined",
max_length=15,
),
),
]
11 changes: 11 additions & 0 deletions BackEnd/profiles/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ def __str__(self):


class Profile(models.Model):
STATUS_CHOICES = [
("undefined", "Undefined"),
("pending", "Pending Moderation"),
("blocked", "Blocked"),
("approved", "Approved"),
("auto_approved", "Auto Approved"),
]

id = models.AutoField(primary_key=True)

name = models.CharField(max_length=100, default=None, null=True)
Expand Down Expand Up @@ -113,6 +121,9 @@ class Profile(models.Model):
created_at = models.DateField(auto_now_add=True)
updated_at = models.DateField(auto_now=True)
completeness = models.SmallIntegerField(default=0)
status = models.CharField(
max_length=15, choices=STATUS_CHOICES, default="undefined"
)

objects = ProfileManager.as_manager()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,17 @@ export default function ChangePassword(props) {
}
)
.then(() => toast.success('Пароль успішно змінено'))
.catch(() =>
toast.error(
'Виникла помилка. Можливо, вказано невірний поточний пароль'
)
);
.catch((error) => {
if (error.response && error.response.data && error.response.data['new_password']) {
const newPasswordError = error.response.data['new_password'][0];
if (newPasswordError === 'This password is too common.') {
toast.error('Пароль занадто поширений. Створіть інший пароль.');
} else if (newPasswordError.startsWith('The password is too similar to the')) {
toast.error('Пароль подібний на іншу персональну інформацію облікового запису. Створіть інший пароль.');
}
} else
toast.error('Виникла помилка. Можливо, вказано невірний поточний пароль');
});
reset();
};

Expand Down
9 changes: 9 additions & 0 deletions FrontEnd/src/components/adminPage/AdminPage.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ToastContainer } from 'react-toastify';
import './AdminGlobal.css';
import Header from './header/Header';
import Menu from './menu/Menu';
Expand All @@ -10,6 +11,7 @@ import { Routes, Route } from 'react-router-dom';
import MainPage from './mainPage/MainPage';
import { useAuth } from '../../hooks';
import Loader from '../loader/Loader';
import AutoApproveDelay from './auto-approve-delay/AutoApproveDelay';

function AdminPage() {
const { isLoading, isAuth, isStaff } = useAuth();
Expand All @@ -21,6 +23,7 @@ function AdminPage() {
<Route path="/users/:id" element={<UserDetail />} />
<Route path="/profiles" element={<ProfilesTable />} />
<Route path="/profile/:id" element={<ProfileDetail />} />
<Route path="/automoderation" element={<AutoApproveDelay />} />
</>
) : (
<Route path="/customadmin/" />
Expand All @@ -37,6 +40,12 @@ function AdminPage() {
</Routes>
</div>
}
<ToastContainer
position="top-right"
autoClose={3000}
theme="colored"
icon={false}
/>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useState, useEffect } from 'react';
import { toast } from 'react-toastify';
import { Tooltip } from 'antd';
import useSWR from 'swr';
import axios from 'axios';
import css from './AutoApproveDelay.module.css';

const AutoApproveDelay = () => {
const fetcher = url => axios.get(url).then(res => res.data);
const url = `${process.env.REACT_APP_BASE_API_URL}/api/admin/automoderation/`;
const { data, mutate } = useSWR(url, fetcher);
const [delay, setDelay] = useState(null);
const [error, setError] = useState(null);

useEffect(() => {
if (data && data.auto_moderation_hours) {
setDelay(data.auto_moderation_hours);
}
}, [data]);

const handleInputChange = (e) => {
let value = Number(e.target.value);
setError(null);
setDelay(value);
if (!(1 <= value && value <= 48) || !Number.isInteger(value)) {
setError('Кількість годин має бути в діапазоні 1-48 години');
}
};

const handleSubmit = () => {
!error && axios.put(`${process.env.REACT_APP_BASE_API_URL}/api/admin/automoderation/`, { 'auto_moderation_hours': delay })
.then(() => { toast.success('Зміни успішно застосовано.'); mutate({ ...data, auto_moderation_hours: delay }); })
.catch((e) => toast.error(e.message));
};
return (
<div className={css['autoapprove-section']}>
<Tooltip
title={'Введіть значення 1-48'}
placement="top"
pointAtCenter={true}>
<input className={css['autoapprove-input']} type="number" step={1} onChange={handleInputChange} value={delay} />
</Tooltip>
{error &&
<p className={css['error-message']}>{error}</p>}
<button className={css['save-button']} onClick={handleSubmit}>Змінити</button>
</div>
);

};

export default AutoApproveDelay;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
.autoapprove-section {
display: flex;
flex-direction: column;
padding: 20px;
gap: 10px;
}

.autoapprove-input {
width: 150px;
height: 20px;
}
.save-button {
display: flex;
padding: 5px 15px;
justify-content: center;
align-items: center;
gap: 10px;
width: 150px;

border-radius: 4px;
border: 1px solid #1F9A7C;
background: #1F9A7C;

box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, 0.04);

/* Button Text */
color: #FFF;
text-align: center;
font-feature-settings: 'calt' off;
text-decoration: none;
font-family: var(--font-main);
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 20px;
letter-spacing: -0.16px;
cursor: pointer;
}

.error-message {
color: rgb(212, 21, 21);
font-family: var(--font-main);
font-size: 14px;
}
4 changes: 4 additions & 0 deletions FrontEnd/src/components/adminPage/mainPage/Text.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ export const MAIN_PAGE_TEXT = [
title: 'Delete Profiles:',
text: 'In case of policy violations or other issues.'
},
{
title: 'Set autoapprove timeout:',
text: 'Specify the time (from 1 to 48 hours) after which the user\'s request to change the banner/logo will be approved automatically.'
}
];
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
margin-top: 25px;
margin-bottom: 180px;
text-align: left;
margin-left: 25px;
}

.main-page-section h1 {
Expand Down
5 changes: 5 additions & 0 deletions FrontEnd/src/components/adminPage/menu/Menu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ const MENU = [
title: 'Компанії',
link: '/customadmin/profiles/'
},
{
id: 'am3',
title: 'Зміна часу автомодерації',
link: '/customadmin/automoderation/'
}
];

function Menu() {
Expand Down

0 comments on commit 7d99307

Please sign in to comment.