diff --git a/admin/src/Membership/MemberBoxSpans.jsx b/admin/src/Membership/MemberBoxSpans.jsx
index ead1cd04..1b140ae7 100644
--- a/admin/src/Membership/MemberBoxSpans.jsx
+++ b/admin/src/Membership/MemberBoxSpans.jsx
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useEffect, useState } from "react";
import "react-day-picker/lib/style.css";
import { Link } from "react-router-dom";
import CollectionTable from "../Components/CollectionTable";
@@ -11,113 +11,117 @@ import { get } from "../gateway";
import { confirmModal } from "../message";
import MembershipPeriodsInput from "./MembershipPeriodsInput";
-class MemberBoxSpans extends React.Component {
- constructor(props) {
- super(props);
- this.collection = new Collection({
- type: Span,
- url: `/membership/member/${props.match.params.member_id}/spans`,
- pageSize: 0,
- includeDeleted: true,
- });
- this.state = { items: [], pending_labaccess_days: "?" };
- this.pending_actions = get({
- url: `/membership/member/${props.match.params.member_id}/pending_actions`,
- }).then((r) => {
- const sum_pending_labaccess_days = r.data.reduce((acc, value) => {
- if (value.action.action === ADD_LABACCESS_DAYS)
- return acc + value.action.value;
- return acc;
- }, 0);
- this.setState({
- pending_labaccess_days: sum_pending_labaccess_days,
+const MemberBoxSpans = (props) => {
+ const collection = new Collection({
+ type: Span,
+ url: `/membership/member/${props.match.params.member_id}/spans`,
+ pageSize: 0,
+ includeDeleted: true,
+ });
+
+ const [pendingLabAccessDays, setPendingLabAccessDays] = useState("?");
+
+ useEffect(() => {
+ // Fetch pending actions
+ const fetchPendingActions = async () => {
+ const response = await get({
+ url: `/membership/member/${props.match.params.member_id}/pending_actions`,
});
- });
- }
+ const sumPendingLabAccessDays = response.data.reduce(
+ (acc, value) => {
+ if (value.action.action === ADD_LABACCESS_DAYS)
+ return acc + value.action.value;
+ return acc;
+ },
+ 0,
+ );
+ setPendingLabAccessDays(sumPendingLabAccessDays);
+ };
+
+ fetchPendingActions();
- componentDidMount() {
- this.unsubscribe = this.collection.subscribe(({ items }) => {
- this.setState({ items });
+ // Subscribe to collection
+ const unsubscribe = collection.subscribe(() => {
+ // No need to handle the subscription data since it's unused
});
- }
- componentWillUnmount() {
- this.unsubscribe();
- }
+ // Cleanup on component unmount
+ return () => {
+ unsubscribe();
+ };
+ }, [props.match.params.member_id]);
- render() {
- const deleteItem = (item) =>
- confirmModal(item.deleteConfirmMessage())
- .then(() => item.del())
- .then(
- () => this.collection.fetch(),
- () => null,
- );
+ const deleteItem = (item) =>
+ confirmModal(item.deleteConfirmMessage())
+ .then(() => item.del())
+ .then(
+ () => collection.fetch(),
+ () => null,
+ );
- return (
-
-
Medlemsperioder
-
- {this.state.pending_labaccess_days} dagar labaccess
- kommer läggas till vid en nyckelsynkronisering.
-
-
-
-
Spans
-
-
(
-
-
-
- {item.id}
-
- |
-
-
- {item.type}
-
- |
-
-
- |
- {item.creation_reason} |
-
-
- |
-
-
- |
-
-
- |
-
- deleteItem(item)}
- className="removebutton"
- >
-
-
- |
-
- )}
- />
-
- );
- }
-}
+ return (
+
+
Medlemsperioder
+
+ {pendingLabAccessDays} dagar labaccess kommer läggas till
+ vid en nyckelsynkronisering.
+
+
+
+
Spans
+
+
(
+
+
+
+ {item.id}
+
+ |
+
+
+ {item.type}
+
+ |
+
+
+ |
+ {item.creation_reason} |
+
+
+ |
+
+
+ |
+
+
+ |
+
+ deleteItem(item)}
+ className="removebutton"
+ >
+
+
+ |
+
+ )}
+ />
+
+ );
+};
export default MemberBoxSpans;
diff --git a/admin/src/Membership/MemberExport.jsx b/admin/src/Membership/MemberExport.jsx
index eff6e5f8..6de16010 100644
--- a/admin/src/Membership/MemberExport.jsx
+++ b/admin/src/Membership/MemberExport.jsx
@@ -1,17 +1,13 @@
-import React from "react";
+import React, { useState } from "react";
import { get } from "../gateway";
-class MemberExport extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- csv_content: null,
- state: "none",
- };
- }
+function MemberExport() {
+ const [csvContent, setCsvContent] = useState(null);
+ const [state, setState] = useState("none");
- exportMembers() {
- this.setState({ state: "loading" });
+ // Function to export members
+ const exportMembers = () => {
+ setState("loading");
get({ url: "/membership/member/all_with_membership" }).then((data) => {
const members = data.data;
@@ -46,38 +42,34 @@ class MemberExport extends React.Component {
]);
}
- this.setState({
- state: "loaded",
- csv_content: rows.map((r) => r.join(",")).join("\n"),
- });
+ setState("loaded");
+ setCsvContent(rows.map((r) => r.join(",")).join("\n"));
});
- }
+ };
- render() {
- return (
-
- );
- }
+ return (
+
+ );
}
export default MemberExport;
diff --git a/admin/src/Membership/MembershipPeriodsInput.js b/admin/src/Membership/MembershipPeriodsInput.js
index 45c27b90..e965494f 100644
--- a/admin/src/Membership/MembershipPeriodsInput.js
+++ b/admin/src/Membership/MembershipPeriodsInput.js
@@ -1,132 +1,118 @@
-import React from "react";
+import React, { useEffect, useState } from "react";
import CategoryPeriodsInput from "../Components/CategoryPeriodsInput";
import CategoryPeriods from "../Models/CategoryPeriods";
import { calculateSpanDiff, filterPeriods } from "../Models/Span";
import auth from "../auth";
import { post } from "../gateway";
-export default class MembershipPeriodsInput extends React.Component {
- constructor(props) {
- super(props);
- this.unsubscribe = [];
- this.categoryPeriodsList = [
- new CategoryPeriods({ category: "labaccess" }),
- new CategoryPeriods({ category: "membership" }),
- new CategoryPeriods({ category: "special_labaccess" }),
- ];
- this.state = { showHistoric: true, saveDisabled: true };
- }
+export default function MembershipPeriodsInput(props) {
+ const [showHistoric, setShowHistoric] = useState(true);
+ const [saveDisabled, setSaveDisabled] = useState(true);
- canSave() {
+ const categoryPeriodsList = [
+ new CategoryPeriods({ category: "labaccess" }),
+ new CategoryPeriods({ category: "membership" }),
+ new CategoryPeriods({ category: "special_labaccess" }),
+ ];
+
+ const canSave = () => {
return (
- this.categoryPeriodsList.every((c) => c.isValid()) &&
- this.categoryPeriodsList.some((c) => c.isDirty())
+ categoryPeriodsList.every((c) => c.isValid()) &&
+ categoryPeriodsList.some((c) => c.isDirty())
);
- }
+ };
- componentDidMount() {
- this.unsubscribe.push(
- this.props.spans.subscribe(({ items }) => {
- this.categoryPeriodsList.forEach((periods) =>
+ useEffect(() => {
+ const unsubscribe = [];
+ unsubscribe.push(
+ props.spans.subscribe(({ items }) => {
+ categoryPeriodsList.forEach((periods) =>
periods.replace(filterPeriods(items, periods.category)),
);
}),
);
- this.categoryPeriodsList.forEach((cp) => {
- this.unsubscribe.push(
- cp.subscribe(() =>
- this.setState({ saveDisabled: !this.canSave() }),
- ),
- );
+ categoryPeriodsList.forEach((cp) => {
+ unsubscribe.push(cp.subscribe(() => setSaveDisabled(!canSave())));
});
- }
-
- componentWillUnmount() {
- this.unsubscribe.forEach((u) => u());
- }
- render() {
- const { showHistoric, saveDisabled } = this.state;
- const { member_id, spans } = this.props;
+ return () => {
+ unsubscribe.forEach((u) => u());
+ };
+ }, [props.spans, categoryPeriodsList]);
- const onSave = () => {
- // Important, need to collect spans to delete and add before doing anything, when spans changes
- // subscriptions on spans will start causing changes of category periods.
- const deleteSpans = [];
- const addSpans = [];
- this.categoryPeriodsList.forEach((cp) => {
- cp.merge();
- calculateSpanDiff({
- items: this.props.spans.items,
- categoryPeriods: cp,
- member_id,
- deleteSpans,
- addSpans,
- });
+ const onSave = () => {
+ const deleteSpans = [];
+ const addSpans = [];
+ categoryPeriodsList.forEach((cp) => {
+ cp.merge();
+ calculateSpanDiff({
+ items: props.spans.items,
+ categoryPeriods: cp,
+ member_id: props.member_id,
+ deleteSpans,
+ addSpans,
});
+ });
- const deleteIds = deleteSpans.map((s) => s.id).join(",");
- const timestamp = new Date().getTime().toString();
- addSpans.forEach(
- (s, i) =>
- (s.creation_reason = (
- timestamp +
- i +
- " gui_edit:" +
- auth.getUsername() +
- " replacing:" +
- deleteIds
- ).slice(0, 255)),
- );
+ const deleteIds = deleteSpans.map((s) => s.id).join(",");
+ const timestamp = new Date().getTime().toString();
+ addSpans.forEach(
+ (s, i) =>
+ (s.creation_reason = (
+ timestamp +
+ i +
+ " gui_edit:" +
+ auth.getUsername() +
+ " replacing:" +
+ deleteIds
+ ).slice(0, 255)),
+ );
- const promises = [];
- promises.push(...deleteSpans.map((s) => s.del()));
- promises.push(...addSpans.map((s) => s.save()));
- Promise.all(promises).then(() => {
- spans.fetch();
+ const promises = [];
+ promises.push(...deleteSpans.map((s) => s.del()));
+ promises.push(...addSpans.map((s) => s.save()));
+ Promise.all(promises).then(() => {
+ props.spans.fetch();
- post({
- url: `/webshop/member/${member_id}/ship_labaccess_orders`,
- expectedDataStatus: "ok",
- });
+ post({
+ url: `/webshop/member/${props.member_id}/ship_labaccess_orders`,
+ expectedDataStatus: "ok",
});
- };
+ });
+ };
- return (
-
- );
- }
+ ))}
+
+
+ );
}
diff --git a/admin/src/Membership/SpanShow.jsx b/admin/src/Membership/SpanShow.jsx
index 2f8de734..2b331a7e 100644
--- a/admin/src/Membership/SpanShow.jsx
+++ b/admin/src/Membership/SpanShow.jsx
@@ -1,42 +1,31 @@
-import React from "react";
-import Span from "../Models/Span";
+import React, { useEffect, useState } from "react";
import * as _ from "underscore";
+import Span from "../Models/Span";
-class SpanShow extends React.Component {
- constructor(props) {
- super(props);
- const { span_id } = props.match.params;
- this.span = Span.get(span_id);
- this.state = { data: {} };
- }
+export default function SpanShow(props) {
+ const { span_id } = props.match.params;
+ const [data, setData] = useState({});
- componentDidMount() {
- this.unsubscribe = this.span.subscribe(() =>
- this.setState({ data: this.span.saved }),
- );
- }
+ const span = Span.get(span_id);
- componentWillUnmount() {
- this.unsubscribe();
- }
+ useEffect(() => {
+ const unsubscribe = span.subscribe(() => setData(span.saved));
- render() {
- const { data } = this.state;
+ // Cleanup subscription on unmount
+ return () => unsubscribe();
+ }, [span]);
- return (
-
-
Medlemsperiod {data.span_id}
-
- {_.keys(data).map((key) => (
-
-
- {key}:
- - {data[key]}
-
- ))}
-
-
- );
- }
+ return (
+
+
Medlemsperiod {data.span_id}
+
+ {_.keys(data).map((key) => (
+
+
- {key}:
+ - {data[key]}
+
+ ))}
+
+
+ );
}
-
-export default SpanShow;