From a8e8b026a295e639744bd7bb7578710392348854 Mon Sep 17 00:00:00 2001 From: om-chauhan1 Date: Fri, 5 Apr 2024 16:10:06 +0530 Subject: [PATCH 1/3] Converted upload_viewer.jsx to functional component --- .../components/uploads/upload_viewer.jsx | 295 ++++++++---------- 1 file changed, 137 insertions(+), 158 deletions(-) diff --git a/app/assets/javascripts/components/uploads/upload_viewer.jsx b/app/assets/javascripts/components/uploads/upload_viewer.jsx index 4640709f55..ce4aa7a8b8 100644 --- a/app/assets/javascripts/components/uploads/upload_viewer.jsx +++ b/app/assets/javascripts/components/uploads/upload_viewer.jsx @@ -1,181 +1,160 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; -import createReactClass from 'create-react-class'; -import { forEach, get } from 'lodash-es'; -import OnClickOutside from 'react-onclickoutside'; -import { connect } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { setUploadViewerMetadata, setUploadPageViews, resetUploadsViews } from '../../actions/uploads_actions.js'; import { formatDateWithoutTime } from '../../utils/date_utils.js'; +import { forEach, get } from 'lodash-es'; +import OnClickOutside from 'react-onclickoutside'; -const UploadViewer = createReactClass({ - displayName: 'UploadViewer', +const UploadViewer = ({ closeUploadViewer, upload, imageFile }) => { + const dispatch = useDispatch(); + const uploadMetadata = useSelector(state => state.uploads.uploadMetadata); + const pageViews = useSelector(state => state.uploads.averageViews); - propTypes: { - upload: PropTypes.object, - closeUploadViewer: PropTypes.func, - }, + const [loadingViews, setLoadingViews] = useState(true); - getInitialState() { - return { - loadingViews: true + useEffect(() => { + dispatch(setUploadViewerMetadata(upload)); + return () => { + dispatch(resetUploadsViews()); }; - }, - - componentDidMount() { - this.props.setUploadViewerMetadata(this.props.upload); - }, + }, [upload]); - componentDidUpdate() { - const metadata = get(this.props.uploadMetadata, `query.pages[${this.props.upload.id}]`); + useEffect(() => { + const metadata = get(uploadMetadata, `query.pages[${upload.id}]`); const fileUsage = get(metadata, 'globalusage', []); - if (fileUsage) { - if (this.state.loadingViews) { - this.handleGetFileViews(fileUsage); - } + if (fileUsage && loadingViews) { + handleGetFileViews(fileUsage); } - }, - - componentWillUnmount() { - this.props.resetUploadsViews(); - }, - - handleGetFileViews(files) { - this.props.setUploadPageViews(files); - this.setState({ - loadingViews: false + }, [uploadMetadata, upload.id, loadingViews]); + + const handleGetFileViews = files => { + dispatch(setUploadPageViews(files)); + setLoadingViews(false); + }; + + const handleClickOutside = () => { + closeUploadViewer(); + }; + + const metadata = get(uploadMetadata, `query.pages[${upload.id}]`); + const imageDescription = get(metadata, 'imageinfo[0].extmetadata.ImageDescription.value'); + const width = get(metadata, 'imageinfo[0].width'); + const height = get(metadata, 'imageinfo[0].height'); + + let size = get(metadata, 'imageinfo[0].size'); + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + const i = Math.floor(Math.log(size) / Math.log(1024)); + size = `${parseFloat((size / (1024 ** i)).toFixed(2))} ${sizes[i]}`; + + const imageUrl = get(metadata, 'imageinfo[0].url'); + + const profileLink = `/users/${encodeURIComponent(upload.uploader)}`; + const author = {upload.uploader}; + const source = get(metadata, 'imageinfo[0].extmetadata.Credit.value'); + const license = get(metadata, 'imageinfo[0].extmetadata.LicenseShortName.value'); + const globalUsage = get(metadata, 'globalusage', []); + let usageTableElements; + if (globalUsage && pageViews !== undefined) { + usageTableElements = globalUsage.map((usage, index) => { + return ( + + {usage.wiki}    + {usage.title}    + {pageViews[index]} + + ); }); - }, - - handleClickOutside() { - this.props.closeUploadViewer(); - }, - - - render() { - const metadata = get(this.props.uploadMetadata, `query.pages[${this.props.upload.id}]`); - const imageDescription = get(metadata, 'imageinfo[0].extmetadata.ImageDescription.value'); - const width = get(metadata, 'imageinfo[0].width'); - const height = get(metadata, 'imageinfo[0].height'); - - let size = get(metadata, 'imageinfo[0].size'); - const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - const i = Math.floor(Math.log(size) / Math.log(1024)); - size = `${parseFloat((size / (1024 ** i)).toFixed(2))} ${sizes[i]}`; - - const imageUrl = get(metadata, 'imageinfo[0].url'); + } - const profileLink = `/users/${encodeURIComponent(this.props.upload.uploader)}`; - const author = {this.props.upload.uploader}; - const source = get(metadata, 'imageinfo[0].extmetadata.Credit.value'); - const license = get(metadata, 'imageinfo[0].extmetadata.LicenseShortName.value'); - const globalUsage = get(metadata, 'globalusage', []); - let usageTableElements; - if (globalUsage && (this.props.pageViews !== undefined)) { - usageTableElements = globalUsage.map((usage, index) => { - return ( - - {usage.wiki}    - {usage.title}    - {this.props.pageViews[index]} + let fileUsageTable; + if (globalUsage.length > 0) { + fileUsageTable = ( +
+

{'\n'}

+

File usage on other wikis

+ + + + + + - ); - }); - } + + + {usageTableElements} + +
WikiArticle NameViews per day
+
+ ); + } + let categoriesList = []; + let categories; + forEach(get(metadata, 'categories', []), (category) => { + categoriesList.push( | ); + categoriesList.push({category.title.slice('Category:'.length)}); + }); + if (categoriesList.length > 0) { + categoriesList = categoriesList.splice(1); + categories = ( +
+

{'\n'}

+

Categories

+ {categoriesList} +
+ ); + } - let fileUsageTable; - if (globalUsage.length > 0) { - fileUsageTable = ( -
-

{'\n'}

-

File usage on other wikis

- - + return ( +
+
+
+
+
+ {upload.file_name} +

Original File{` (${width} X ${height} pixels, file size: ${size})`}

+

Description

+

+

+
+
+ - - - + + + + + + + + + + + + + + - - - {usageTableElements}
WikiArticle NameViews per dayDate: {formatDateWithoutTime(upload.uploaded_at)}
Author: {author}
Source:  +
License: {license}{'\n'}
-
- ); - } - let categoriesList = []; - let categories; - forEach(get(metadata, 'categories', []), (category) => { - categoriesList.push( | ); - categoriesList.push({category.title.slice('Category:'.length)}); - }); - if (categoriesList.length > 0) { - categoriesList = categoriesList.splice(1); - categories = ( -
-

{'\n'}

-

Categories

- {categoriesList} -
- ); - } - - return ( -
-
-
-
-
- {this.props.upload.file_name} -

Original File{` (${width} X ${height} pixels, file size: ${size})`}

-

Description

-

-

-
- - - - - - - - - - - - - - - - - - - -
Date: {formatDateWithoutTime(this.props.upload.uploaded_at)}
Author: {author}
Source:  -
License: {license}{'\n'}
- {categories} - {fileUsageTable} -
-
-
- View on Commons + {categories} + {fileUsageTable}
- ); - } -}); - -const mapStateToProps = state => ({ - uploadMetadata: state.uploads.uploadMetadata, - pageViews: state.uploads.averageViews -}); +
+ View on Commons +
+ + ); +}; -const mapDispatchToProps = { - setUploadViewerMetadata, - setUploadPageViews, - resetUploadsViews +UploadViewer.propTypes = { + upload: PropTypes.object, + closeUploadViewer: PropTypes.func, + imageFile: PropTypes.string }; -export default connect(mapStateToProps, mapDispatchToProps)(OnClickOutside(UploadViewer)); +export default OnClickOutside(UploadViewer); From b9663cdbeca16a7675d95fc0a540c5b9e81d54f0 Mon Sep 17 00:00:00 2001 From: om-chauhan1 Date: Fri, 5 Apr 2024 16:38:53 +0530 Subject: [PATCH 2/3] Extended i18n over string literals --- .../components/uploads/upload_viewer.jsx | 26 +++++++++---------- config/locales/en.yml | 12 +++++++++ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/components/uploads/upload_viewer.jsx b/app/assets/javascripts/components/uploads/upload_viewer.jsx index ce4aa7a8b8..11e3243c8e 100644 --- a/app/assets/javascripts/components/uploads/upload_viewer.jsx +++ b/app/assets/javascripts/components/uploads/upload_viewer.jsx @@ -28,7 +28,7 @@ const UploadViewer = ({ closeUploadViewer, upload, imageFile }) => { } }, [uploadMetadata, upload.id, loadingViews]); - const handleGetFileViews = files => { + const handleGetFileViews = (files) => { dispatch(setUploadPageViews(files)); setLoadingViews(false); }; @@ -72,13 +72,13 @@ const UploadViewer = ({ closeUploadViewer, upload, imageFile }) => { fileUsageTable = (

{'\n'}

-

File usage on other wikis

+

{I18n.t('uploads.file_usage')}

- - - + + + @@ -99,7 +99,7 @@ const UploadViewer = ({ closeUploadViewer, upload, imageFile }) => { categories = (

{'\n'}

-

Categories

+

{I18n.t('uploads.categories')}

{categoriesList}
); @@ -114,27 +114,27 @@ const UploadViewer = ({ closeUploadViewer, upload, imageFile }) => {
{upload.file_name} -

Original File{` (${width} X ${height} pixels, file size: ${size})`}

-

Description

+

{I18n.t('uploads.original_file')}{` (${width} X ${height} pixels, file size: ${size})`}

+

{I18n.t('uploads.description')}

WikiArticle NameViews per day{I18n.t('uploads.wiki_big')}{I18n.t('uploads.article_name')}{I18n.t('uploads.views_per_day')}
- + - + - + - + @@ -145,7 +145,7 @@ const UploadViewer = ({ closeUploadViewer, upload, imageFile }) => {
- View on Commons + {I18n.t('uploads.view_commons')}
); diff --git a/config/locales/en.yml b/config/locales/en.yml index ccdf6b0ebe..c37456555a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1405,13 +1405,21 @@ en: button: Update uploads: + article_name: Article Name + author: "Author:" + categories: Categories credit: Credit + date: "Date:" + description: Description file_name: File Name + file_usage: File usage on other wikis header: Files Uploaded to Wikimedia Commons image: Image label: Uploads + license: "License:" loading: Loading uploads... none: This class has not contributed any images or other media files to Wikimedia Commons. + original_file: Original File select_label: Filter by uploader time_doc: The time of each upload in your local time uploaded_at: Upload Time @@ -1424,7 +1432,11 @@ en: usages: Usages gallery_view: Gallery View list_view: List View + source: "Source:" tile_view: Tile View + views_per_day: Views per day + view_commons: View on Commons + wiki_big: Wiki users: already_enrolled: That user is already enrolled! From 7788004ab8ba513f864e41fdf502d91223af8cf6 Mon Sep 17 00:00:00 2001 From: om-chauhan1 Date: Thu, 18 Apr 2024 22:05:58 +0530 Subject: [PATCH 3/3] fixed onOutside click functioning and converted loadsh 'forEach' to native js --- .../javascripts/components/uploads/upload_viewer.jsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/components/uploads/upload_viewer.jsx b/app/assets/javascripts/components/uploads/upload_viewer.jsx index 11e3243c8e..2a4dca1b44 100644 --- a/app/assets/javascripts/components/uploads/upload_viewer.jsx +++ b/app/assets/javascripts/components/uploads/upload_viewer.jsx @@ -3,8 +3,8 @@ import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; import { setUploadViewerMetadata, setUploadPageViews, resetUploadsViews } from '../../actions/uploads_actions.js'; import { formatDateWithoutTime } from '../../utils/date_utils.js'; -import { forEach, get } from 'lodash-es'; -import OnClickOutside from 'react-onclickoutside'; +import { get } from 'lodash-es'; +import useOutsideClick from '../../hooks/useOutsideClick.js'; const UploadViewer = ({ closeUploadViewer, upload, imageFile }) => { const dispatch = useDispatch(); @@ -36,6 +36,7 @@ const UploadViewer = ({ closeUploadViewer, upload, imageFile }) => { const handleClickOutside = () => { closeUploadViewer(); }; + const ref = useOutsideClick(handleClickOutside); const metadata = get(uploadMetadata, `query.pages[${upload.id}]`); const imageDescription = get(metadata, 'imageinfo[0].extmetadata.ImageDescription.value'); @@ -90,7 +91,7 @@ const UploadViewer = ({ closeUploadViewer, upload, imageFile }) => { } let categoriesList = []; let categories; - forEach(get(metadata, 'categories', []), (category) => { + (metadata?.categories ?? []).forEach((category) => { categoriesList.push( | ); categoriesList.push({category.title.slice('Category:'.length)}); }); @@ -106,7 +107,7 @@ const UploadViewer = ({ closeUploadViewer, upload, imageFile }) => { } return ( -
+
Date: {I18n.t('uploads.date')}  {formatDateWithoutTime(upload.uploaded_at)}
Author: {I18n.t('uploads.author')}  {author}
Source: {I18n.t('uploads.source')} 
License: {I18n.t('uploads.license')}  {license} {'\n'}