This is an automated email from the ASF dual-hosted git repository.

robin0716 pushed a commit to branch feat/1.4.0/personal
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git

commit a4c8256fbd82315173f8e1d247f5cce2adeeedf5
Author: robin <[email protected]>
AuthorDate: Tue Aug 13 17:42:12 2024 +0800

    feat(admin): Improve the badge list
---
 .../pages/Admin/Badges/components/Action/index.tsx | 15 ++--
 ui/src/pages/Admin/Badges/index.tsx                | 96 +++++++++++++++-------
 ui/src/services/admin/{index.ts => badges.ts}      | 30 +++++--
 ui/src/services/admin/index.ts                     |  1 +
 4 files changed, 97 insertions(+), 45 deletions(-)

diff --git a/ui/src/pages/Admin/Badges/components/Action/index.tsx 
b/ui/src/pages/Admin/Badges/components/Action/index.tsx
index 77601cbb..9ec18379 100644
--- a/ui/src/pages/Admin/Badges/components/Action/index.tsx
+++ b/ui/src/pages/Admin/Badges/components/Action/index.tsx
@@ -23,23 +23,20 @@ import { useTranslation } from 'react-i18next';
 import { Icon } from '@/components';
 
 interface Props {
-  badgeData;
+  onSelect: (eventKey: string | null) => void;
 }
-
-const UserOperation = ({ badgeData }: Props) => {
+const BadgeOperation = ({ onSelect }: Props) => {
   const { t } = useTranslation('translation', { keyPrefix: 'admin.badges' });
 
-  console.log(badgeData);
-
   return (
     <td className="text-end">
-      <Dropdown>
+      <Dropdown onSelect={onSelect}>
         <Dropdown.Toggle variant="link" className="no-toggle p-0">
           <Icon name="three-dots-vertical" title={t('action')} />
         </Dropdown.Toggle>
         <Dropdown.Menu align="end">
-          <Dropdown.Item>{t('active')}</Dropdown.Item>
-          <Dropdown.Item>{t('deactivate')}</Dropdown.Item>
+          <Dropdown.Item eventKey="active">{t('active')}</Dropdown.Item>
+          <Dropdown.Item eventKey="inactive">{t('deactivate')}</Dropdown.Item>
           <Dropdown.Divider />
           <Dropdown.Item>{t('show_logs')}</Dropdown.Item>
         </Dropdown.Menu>
@@ -48,4 +45,4 @@ const UserOperation = ({ badgeData }: Props) => {
   );
 };
 
-export default UserOperation;
+export default BadgeOperation;
diff --git a/ui/src/pages/Admin/Badges/index.tsx 
b/ui/src/pages/Admin/Badges/index.tsx
index 28854012..6c74f3ce 100644
--- a/ui/src/pages/Admin/Badges/index.tsx
+++ b/ui/src/pages/Admin/Badges/index.tsx
@@ -22,33 +22,50 @@ import { Form, Table, Stack } from 'react-bootstrap';
 import { useSearchParams } from 'react-router-dom';
 import { useTranslation } from 'react-i18next';
 
-import { QueryGroup } from '@/components';
+import classNames from 'classnames';
+
+import { Empty, Icon, Pagination, QueryGroup } from '@/components';
 import * as Type from '@/common/interface';
+import { useQueryBadges, updateBadgeStatus } from '@/services/admin/badges';
 
 import Action from './components/Action';
 
 const BadgeFilterKeys: Type.BadgeFilterBy[] = ['all', 'active', 'inactive'];
 
-// const bgMap = {
-//   normal: 'text-bg-success',
-//   suspended: 'text-bg-danger',
-//   deleted: 'text-bg-danger',
-//   inactive: 'text-bg-secondary',
-// };
+const bgMap = {
+  active: 'text-bg-success',
+  inactive: 'text-bg-secondary',
+};
+
+const PAGE_SIZE = 10;
 
 const Users: FC = () => {
   const { t } = useTranslation('translation', { keyPrefix: 'admin.badges' });
 
   const [urlSearchParams, setUrlSearchParams] = useSearchParams();
+  const curPage = Number(urlSearchParams.get('page') || '1');
   const curFilter = urlSearchParams.get('filter') || BadgeFilterKeys[0];
   const curQuery = urlSearchParams.get('query') || '';
 
+  const { data, isLoading, mutate } = useQueryBadges({
+    page: curPage,
+    pageSize: PAGE_SIZE,
+    query: curQuery,
+    ...(curFilter === 'all' ? {} : { status: curFilter }),
+  });
+
   const handleFilter = (e) => {
     urlSearchParams.set('query', e.target.value);
     urlSearchParams.delete('page');
     setUrlSearchParams(urlSearchParams);
   };
 
+  const handleBadgeStatus = (badgeId, status) => {
+    updateBadgeStatus({ id: badgeId, status }).then(() => {
+      mutate();
+    });
+  };
+
   return (
     <>
       <h3 className="mb-4">{t('title')}</h3>
@@ -85,36 +102,57 @@ const Users: FC = () => {
           </tr>
         </thead>
         <tbody className="align-middle">
-          <tr>
-            <td className="d-flex align-items-center">
-              <img
-                
src="https://s3-alpha-sig.figma.com/img/b6d9/2c6b/dfa4017fd4654f72c13bfc406377416a?Expires=1723420800&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=lp0b2MuP5yiv7IB4yEuhFk--W9D5CWsud77ftgjtdFrSIPPsIxcnZxz-RyLl40euIysaQLVVWwvYqJP75wLnccCQ1XbzwKfU1sOj3Z52jMTLMZ5PGwYL~dnx0sUJVv3khew7Xe8FiebLTwK4yV62jlW2RYq~HvK3s3RL5z9ZrkSnZUIWOC1nD~RTlsS9K3-hJ9GHwSCA9i0VupM5qHBMgxZDstTy6MO5VnACCCD1865NsKpkLM770wlVXP7XARVl5AhcRFYr0J8VTjccwg3dRHvOUUy4sM0wOqRctX7dgQfp1V-bc49RNcO0CkHifof2hn4oLyaC4fU
 [...]
-                className="rounded-circle bg-white me-2"
-                width="32px"
-                height="32px"
-                alt="badge"
+          {data?.list.map((badge) => (
+            <tr>
+              <td className="d-flex align-items-center">
+                {badge.icon?.startsWith('http') ? (
+                  <img
+                    src={badge.icon}
+                    width={32}
+                    height={32}
+                    alt={badge.name}
+                    className="me-3"
+                  />
+                ) : (
+                  <Icon
+                    name={badge?.icon}
+                    size="32px"
+                    className={classNames(
+                      'lh-1 me-3',
+                      badge?.level === 1 && 'bronze',
+                      badge?.level === 2 && 'silver',
+                      badge?.level === 3 && 'gold',
+                    )}
+                  />
+                )}
+                <div>
+                  <div className="text-primary">{badge.name}</div>
+                  <div className="text-small">{badge.description}</div>
+                </div>
+              </td>
+
+              <td>{badge.group_name}</td>
+              <td className="text-primary">{badge.award_count}</td>
+              <td>
+                <span className={classNames('badge', bgMap[badge.status])}>
+                  {t(badge.status)}
+                </span>
+              </td>
+              <Action
+                onSelect={(status) => handleBadgeStatus(badge.id, status)}
               />
-              <div>
-                <div className="text-primary">Nice Question</div>
-                <div className="text-small">Question score of 10 or more.</div>
-              </div>
-            </td>
-
-            <td>Community Badges</td>
-            <td className="text-primary">200</td>
-            <td>Active</td>
-            <Action badgeData={{}} />
-          </tr>
+            </tr>
+          ))}
         </tbody>
       </Table>
-      {/* {Number(data?.count) <= 0 && !isLoading && <Empty />} */}
-      {/* <div className="mt-4 mb-2 d-flex justify-content-center">
+      {Number(data?.count) <= 0 && !isLoading && <Empty />}
+      <div className="mt-4 mb-2 d-flex justify-content-center">
         <Pagination
           currentPage={curPage}
           totalSize={data?.count || 0}
           pageSize={PAGE_SIZE}
         />
-      </div> */}
+      </div>
     </>
   );
 };
diff --git a/ui/src/services/admin/index.ts b/ui/src/services/admin/badges.ts
similarity index 59%
copy from ui/src/services/admin/index.ts
copy to ui/src/services/admin/badges.ts
index ce64c511..b984164e 100644
--- a/ui/src/services/admin/index.ts
+++ b/ui/src/services/admin/badges.ts
@@ -17,10 +17,26 @@
  * under the License.
  */
 
-export * from './answer';
-export * from './flag';
-export * from './question';
-export * from './settings';
-export * from './users';
-export * from './dashboard';
-export * from './plugins';
+import qs from 'qs';
+import useSWR from 'swr';
+
+import request from '@/utils/request';
+import type * as Type from '@/common/interface';
+
+export const useQueryBadges = (params) => {
+  const apiUrl = `/answer/admin/api/badges?${qs.stringify(params)}`;
+  const { data, error, mutate } = useSWR<Type.ListResult, Error>(
+    apiUrl,
+    request.instance.get,
+  );
+  return {
+    data,
+    isLoading: !data && !error,
+    error,
+    mutate,
+  };
+};
+
+export const updateBadgeStatus = (params) => {
+  return request.put('/answer/admin/api/badge/status', params);
+};
diff --git a/ui/src/services/admin/index.ts b/ui/src/services/admin/index.ts
index ce64c511..af83d365 100644
--- a/ui/src/services/admin/index.ts
+++ b/ui/src/services/admin/index.ts
@@ -24,3 +24,4 @@ export * from './settings';
 export * from './users';
 export * from './dashboard';
 export * from './plugins';
+export * from './badges';

Reply via email to