diff --git a/BackEnd/profiles/serializers.py b/BackEnd/profiles/serializers.py
index 1f2e3aa75..078edaf14 100644
--- a/BackEnd/profiles/serializers.py
+++ b/BackEnd/profiles/serializers.py
@@ -56,6 +56,18 @@ def to_internal_value(self, data):
return ProfileImage.objects.filter(uuid=data, is_deleted=False).first()
+class ProfileImageFieldApprovedStatus(ProfileImageField):
+ def to_representation(self, value):
+ if not value.is_deleted:
+ return {
+ "uuid": value.uuid,
+ "path": self.context["request"].build_absolute_uri(
+ value.image_path.url
+ ),
+ "is_approved": value.is_approved,
+ }
+
+
class ProfileListSerializer(serializers.ModelSerializer):
activities = ActivitySerializer(many=True, read_only=True)
categories = CategorySerializer(many=True, read_only=True)
@@ -200,8 +212,8 @@ class ProfileOwnerDetailViewSerializer(serializers.ModelSerializer):
email = serializers.ReadOnlyField(source="person.email")
regions = RegionSerializer(many=True, read_only=True)
regions_ukr_display = serializers.SerializerMethodField()
- banner = ProfileImageField()
- logo = ProfileImageField()
+ banner = ProfileImageFieldApprovedStatus()
+ logo = ProfileImageFieldApprovedStatus()
class Meta:
model = Profile
@@ -231,6 +243,8 @@ class Meta:
"banner",
"logo",
"is_deleted",
+ "status",
+ "status_updated_at",
)
read_only_fields = (
"id",
@@ -258,6 +272,8 @@ class Meta:
"banner",
"logo",
"is_deleted",
+ "status",
+ "status_updated_at",
)
def get_regions_ukr_display(self, obj) -> str:
diff --git a/FrontEnd/public/img/moderation-icon.png b/FrontEnd/public/img/moderation-icon.png
new file mode 100644
index 000000000..c2187312d
Binary files /dev/null and b/FrontEnd/public/img/moderation-icon.png differ
diff --git a/FrontEnd/src/components/MiniComponents/PendingModerationIcon/PendingStatus.jsx b/FrontEnd/src/components/MiniComponents/PendingModerationIcon/PendingStatus.jsx
new file mode 100644
index 000000000..3550ad515
--- /dev/null
+++ b/FrontEnd/src/components/MiniComponents/PendingModerationIcon/PendingStatus.jsx
@@ -0,0 +1,40 @@
+import { Tooltip } from 'antd';
+import styles from './PendingStatus.module.css';
+
+const PendingStatus = ({ profile, elementType }) => {
+
+ const bannerApproved = profile?.banner.is_approved;
+ const logoApproved = profile?.logo.is_approved;
+
+ const shouldShowTooltip = (elementType === 'banner' && bannerApproved === false)
+ || (elementType === 'logo' && logoApproved === false);
+
+ const formattedDate = new Date(profile?.status_updated_at).toLocaleString('uk-UA', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ });
+
+ const tooltipText = `Статус модерації: Очікується. Час відправки запиту: ${formattedDate}`;
+
+ return (
+ (profile?.status === 'pending' && shouldShowTooltip) ? (
+
+
+
+
+
+ ) : null
+ );
+};
+
+export default PendingStatus;
diff --git a/FrontEnd/src/components/MiniComponents/PendingModerationIcon/PendingStatus.module.css b/FrontEnd/src/components/MiniComponents/PendingModerationIcon/PendingStatus.module.css
new file mode 100644
index 000000000..2c4bc5e06
--- /dev/null
+++ b/FrontEnd/src/components/MiniComponents/PendingModerationIcon/PendingStatus.module.css
@@ -0,0 +1,7 @@
+.tooltip-container{
+ display: flex;
+ position:absolute;
+ padding-top: 5px;
+ padding-left: 3px;
+ }
+
\ No newline at end of file
diff --git a/FrontEnd/src/components/ProfileDetail/ProfileDetailPage.jsx b/FrontEnd/src/components/ProfileDetail/ProfileDetailPage.jsx
index adfa78170..0ffe54a55 100644
--- a/FrontEnd/src/components/ProfileDetail/ProfileDetailPage.jsx
+++ b/FrontEnd/src/components/ProfileDetail/ProfileDetailPage.jsx
@@ -11,6 +11,7 @@ import DetailedInfoSection from './DetailedInfo/DetailedInfoSection';
import BannerImage from './BannerImage';
import { ActiveLinksContext } from '../../context/ActiveLinksContext';
import classes from './ProfileDetailPage.module.css';
+import PendingStatus from '../MiniComponents/PendingModerationIcon/PendingStatus';
function ProfileDetailPage({ isAuthorized }) {
const [activeLinks, setActiveLinks] = useState([]);
@@ -31,7 +32,7 @@ function ProfileDetailPage({ isAuthorized }) {
const notRequiredData = ['address', 'banner', 'logo', 'common_info', 'edrpou', 'rnokpp', 'founded', 'official_name', 'product_info', 'service_info', 'startup_idea', 'logistics', 'cooperation'];
const containsNotRequiredData = fetchedProfile ? Object.keys(fetchedProfile).some(key => notRequiredData.includes(key) && fetchedProfile[key] !== '' && fetchedProfile[key] !== null) : false;
- return (error && error.response.status !== 401) ? (
+ return (error && error.status !== 401) ? (
) : (
@@ -39,6 +40,9 @@ function ProfileDetailPage({ isAuthorized }) {
) : (
+
+
{
+
const backgroundImage = {
background: `url(${value}) lightgray 50% / cover no-repeat`,
};
@@ -56,11 +59,18 @@ const ImageField = ({
);
return (
-
+
-
Зображення для карток
-
+
>
)}
{name === 'logo' && value && (
-
-
- {renderInput()}
- {renderUpdateImageLabel('змінити')}
- {renderDeleteButton('видалити')}
+
+
+
+
+ {renderInput()}
+ {renderUpdateImageLabel('змінити')}
+ {renderDeleteButton('видалити')}
+
)}
diff --git a/FrontEnd/src/components/ProfilePage/FormComponents/FormFields/ImageField.module.css b/FrontEnd/src/components/ProfilePage/FormComponents/FormFields/ImageField.module.css
index 17e58a7a1..118ccd3ee 100644
--- a/FrontEnd/src/components/ProfilePage/FormComponents/FormFields/ImageField.module.css
+++ b/FrontEnd/src/components/ProfilePage/FormComponents/FormFields/ImageField.module.css
@@ -175,4 +175,4 @@ button {
.fields__field--notrequired {
padding-top: 2px;
-}
\ No newline at end of file
+}
diff --git a/FrontEnd/src/components/ProfilePage/FormComponents/GeneralInfo.jsx b/FrontEnd/src/components/ProfilePage/FormComponents/GeneralInfo.jsx
index c59298f9d..dc6f0cf5c 100644
--- a/FrontEnd/src/components/ProfilePage/FormComponents/GeneralInfo.jsx
+++ b/FrontEnd/src/components/ProfilePage/FormComponents/GeneralInfo.jsx
@@ -525,6 +525,7 @@ const GeneralInfo = (props) => {
value={bannerImage}
error={bannerImageError}
onDeleteImage={deleteImageHandler}
+ profile={mainProfile}
/>
{
value={logoImage}
error={logoImageError}
onDeleteImage={deleteImageHandler}
+ profile={mainProfile}
/>