PluginCard.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import React, { useState } from 'react';
  2. import Link from 'next/link';
  3. import { apiv3Delete, apiv3Put } from '~/client/util/apiv3-client';
  4. import { toastSuccess, toastError } from '~/client/util/toastr';
  5. import styles from './PluginCard.module.scss';
  6. type Props = {
  7. id: string,
  8. name: string,
  9. url: string,
  10. isEnalbed: boolean,
  11. mutate: () => void,
  12. desc?: string,
  13. }
  14. export const PluginCard = (props: Props): JSX.Element => {
  15. const {
  16. id, name, url, isEnalbed, desc, mutate,
  17. } = props;
  18. const PluginCardButton = (): JSX.Element => {
  19. const [isEnabled, setState] = useState<boolean>(isEnalbed);
  20. const onChangeHandler = async() => {
  21. try {
  22. if (isEnabled) {
  23. const reqUrl = `/plugins/${id}/deactivate`;
  24. await apiv3Put(reqUrl);
  25. setState(!isEnabled);
  26. toastSuccess('Plugin Deactivated');
  27. }
  28. else {
  29. const reqUrl = `/plugins/${id}/activate`;
  30. await apiv3Put(reqUrl);
  31. setState(!isEnabled);
  32. toastSuccess('Plugin Activated');
  33. }
  34. }
  35. catch (err) {
  36. toastError('pluginIsEnabled', err);
  37. }
  38. };
  39. return (
  40. <div className={`${styles.plugin_card}`}>
  41. <div className="switch">
  42. <label className="switch__label">
  43. <input
  44. type="checkbox"
  45. className="switch__input"
  46. onChange={() => onChangeHandler()}
  47. checked={isEnabled}
  48. />
  49. <span className="switch__content"></span>
  50. <span className="switch__circle"></span>
  51. </label>
  52. </div>
  53. </div>
  54. );
  55. };
  56. const PluginDeleteButton = (): JSX.Element => {
  57. const onClickPluginDeleteBtnHandler = async() => {
  58. const reqUrl = `/plugins/${id}/remove`;
  59. try {
  60. await apiv3Delete(reqUrl);
  61. toastSuccess(`${name} Deleted`);
  62. }
  63. catch (err) {
  64. toastError('pluginDelete', err);
  65. }
  66. finally {
  67. mutate();
  68. }
  69. };
  70. return (
  71. <div className="">
  72. <button
  73. type="submit"
  74. className="btn btn-primary"
  75. onClick={() => onClickPluginDeleteBtnHandler()}
  76. >
  77. Delete
  78. </button>
  79. </div>
  80. );
  81. };
  82. // TODO: Refactor commented out areas.
  83. return (
  84. <div className="card shadow border-0" key={name}>
  85. <div className="card-body px-5 py-4 mt-3">
  86. <div className="row mb-3">
  87. <div className="col-9">
  88. <h2 className="card-title h3 border-bottom pb-2 mb-3">
  89. <Link href={`${url}`}>{name}</Link>
  90. </h2>
  91. <p className="card-text text-muted">{desc}</p>
  92. </div>
  93. <div className='col-3'>
  94. <div>
  95. <PluginCardButton />
  96. </div>
  97. <div className="mt-4">
  98. <PluginDeleteButton />
  99. </div>
  100. </div>
  101. </div>
  102. <div className="row">
  103. <div className="col-12 d-flex flex-wrap gap-2">
  104. {/* {topics?.map((topic: string) => {
  105. return (
  106. <span key={`${name}-${topic}`} className="badge rounded-1 mp-bg-light-blue text-dark fw-normal">
  107. {topic}
  108. </span>
  109. );
  110. })} */}
  111. </div>
  112. </div>
  113. </div>
  114. <div className="card-footer px-5 border-top-0 mp-bg-light-blue">
  115. <p className="d-flex justify-content-between align-self-center mb-0">
  116. <span>
  117. {/* {owner.login === 'weseek' ? <FontAwesomeIcon icon={faCircleCheck} className="me-1 text-primary" /> : <></>}
  118. <a href={owner.html_url} target="_blank" rel="noreferrer">
  119. {owner.login}
  120. </a> */}
  121. </span>
  122. {/* <span>
  123. <FontAwesomeIcon icon={faCircleArrowDown} className="me-1" /> {stargazersCount}
  124. </span> */}
  125. </p>
  126. </div>
  127. </div>
  128. );
  129. };