@calimero-network/mero-react 4.1.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -268,14 +268,19 @@ function MeroProvider({
268
268
  },
269
269
  [timeoutMs, tokenStore]
270
270
  );
271
- const checkAuth = react.useCallback(async (instance) => {
272
- try {
273
- await instance.admin.getContexts();
274
- return true;
275
- } catch {
276
- return false;
277
- }
278
- }, []);
271
+ const checkAuth = react.useCallback(
272
+ async (instance) => {
273
+ const accessToken = tokenStore.getTokens()?.access_token;
274
+ if (!accessToken) return false;
275
+ try {
276
+ const { valid } = await instance.auth.validateToken(accessToken);
277
+ return valid;
278
+ } catch {
279
+ return false;
280
+ }
281
+ },
282
+ [tokenStore]
283
+ );
279
284
  const connectToNode = react.useCallback(
280
285
  (url) => {
281
286
  if (!isBrowser) return;
@@ -1364,6 +1369,49 @@ function useAsyncMutation() {
1364
1369
  );
1365
1370
  return { loading, error, run, setError };
1366
1371
  }
1372
+ function useAsyncResource(fetcher, initialValue, deps) {
1373
+ const mountedRef = useMountedRef();
1374
+ const [data, setData] = react.useState(initialValue);
1375
+ const [loading, setLoading] = react.useState(false);
1376
+ const [error, setError] = react.useState(null);
1377
+ const reqRef = react.useRef(0);
1378
+ const fetcherRef = react.useRef(fetcher);
1379
+ fetcherRef.current = fetcher;
1380
+ const initialRef = react.useRef(initialValue);
1381
+ const refetch = react.useCallback(async () => {
1382
+ const seq = ++reqRef.current;
1383
+ const fn = fetcherRef.current;
1384
+ if (!fn) {
1385
+ if (mountedRef.current && seq === reqRef.current) {
1386
+ setData(initialRef.current);
1387
+ setError(null);
1388
+ setLoading(false);
1389
+ }
1390
+ return;
1391
+ }
1392
+ if (mountedRef.current) {
1393
+ setLoading(true);
1394
+ setError(null);
1395
+ }
1396
+ try {
1397
+ const result = await fn();
1398
+ if (mountedRef.current && seq === reqRef.current) setData(result);
1399
+ } catch (err) {
1400
+ if (mountedRef.current && seq === reqRef.current) setError(toError(err));
1401
+ } finally {
1402
+ if (mountedRef.current && seq === reqRef.current) setLoading(false);
1403
+ }
1404
+ }, deps);
1405
+ react.useEffect(() => {
1406
+ reqRef.current += 1;
1407
+ setData(initialRef.current);
1408
+ setError(null);
1409
+ }, deps);
1410
+ react.useEffect(() => {
1411
+ void refetch();
1412
+ }, [refetch]);
1413
+ return { data, loading, error, refetch };
1414
+ }
1367
1415
  function sleep(ms) {
1368
1416
  return new Promise((resolve) => {
1369
1417
  setTimeout(resolve, ms);
@@ -1448,123 +1496,42 @@ function useSubscription(contextIds, callback) {
1448
1496
  }
1449
1497
  function useContexts(applicationId) {
1450
1498
  const { mero } = useMero();
1451
- const [contexts, setContexts] = react.useState([]);
1452
- const [loading, setLoading] = react.useState(false);
1453
- const [error, setError] = react.useState(null);
1454
- const mountedRef = useMountedRef();
1455
- const refetch = react.useCallback(async () => {
1456
- if (!mero) return;
1457
- if (mountedRef.current) {
1458
- setLoading(true);
1459
- setError(null);
1460
- }
1461
- try {
1499
+ const { data, loading, error, refetch } = useAsyncResource(
1500
+ mero ? async () => {
1462
1501
  const response = applicationId ? await mero.admin.getContextsForApplication(applicationId) : await mero.admin.getContexts();
1463
- const list = mapApplicationContexts(response.contexts ?? []);
1464
- if (mountedRef.current) {
1465
- setContexts(list);
1466
- }
1467
- } catch (err) {
1468
- const errorValue = toError(err);
1469
- if (mountedRef.current) {
1470
- setError(errorValue);
1471
- }
1472
- } finally {
1473
- if (mountedRef.current) {
1474
- setLoading(false);
1475
- }
1476
- }
1477
- }, [mero, applicationId]);
1478
- react.useEffect(() => {
1479
- void refetch();
1480
- }, [refetch]);
1481
- return { contexts, loading, error, refetch };
1502
+ return mapApplicationContexts(response.contexts ?? []);
1503
+ } : null,
1504
+ [],
1505
+ [mero, applicationId]
1506
+ );
1507
+ return { contexts: data, loading, error, refetch };
1482
1508
  }
1483
1509
  function useApplicationContexts(applicationId) {
1484
1510
  return useContexts(applicationId);
1485
1511
  }
1486
1512
  function useGroupMembers(groupId) {
1487
1513
  const { mero } = useMero();
1488
- const [members, setMembers] = react.useState([]);
1489
- const [selfIdentity, setSelfIdentity] = react.useState(null);
1490
- const [loading, setLoading] = react.useState(false);
1491
- const [error, setError] = react.useState(null);
1492
- const mountedRef = useMountedRef();
1493
- const refetch = react.useCallback(async () => {
1494
- if (!mero || !groupId) {
1495
- if (mountedRef.current) {
1496
- setMembers([]);
1497
- setSelfIdentity(null);
1498
- setError(null);
1499
- setLoading(false);
1500
- }
1501
- return;
1502
- }
1503
- if (mountedRef.current) {
1504
- setLoading(true);
1505
- setError(null);
1506
- }
1507
- try {
1508
- const response = await mero.admin.listGroupMembers(groupId);
1509
- if (mountedRef.current) {
1510
- setMembers(response.members ?? []);
1511
- setSelfIdentity(response.selfIdentity ?? null);
1512
- }
1513
- } catch (err) {
1514
- const errorValue = toError(err);
1515
- if (mountedRef.current) {
1516
- setError(errorValue);
1517
- }
1518
- } finally {
1519
- if (mountedRef.current) {
1520
- setLoading(false);
1521
- }
1522
- }
1523
- }, [groupId, mero, mountedRef]);
1524
- react.useEffect(() => {
1525
- void refetch();
1526
- }, [refetch]);
1527
- return { members, selfIdentity, loading, error, refetch };
1514
+ const { data, loading, error, refetch } = useAsyncResource(
1515
+ mero && groupId ? () => mero.admin.listGroupMembers(groupId) : null,
1516
+ null,
1517
+ [mero, groupId]
1518
+ );
1519
+ return {
1520
+ members: data?.members ?? [],
1521
+ selfIdentity: data?.selfIdentity ?? null,
1522
+ loading,
1523
+ error,
1524
+ refetch
1525
+ };
1528
1526
  }
1529
1527
  function useGroupContexts(groupId) {
1530
1528
  const { mero } = useMero();
1531
- const [contexts, setContexts] = react.useState([]);
1532
- const [loading, setLoading] = react.useState(false);
1533
- const [error, setError] = react.useState(null);
1534
- const mountedRef = useMountedRef();
1535
- const refetch = react.useCallback(async () => {
1536
- if (!mero || !groupId) {
1537
- if (mountedRef.current) {
1538
- setContexts([]);
1539
- setError(null);
1540
- setLoading(false);
1541
- }
1542
- return;
1543
- }
1544
- if (mountedRef.current) {
1545
- setLoading(true);
1546
- setError(null);
1547
- }
1548
- try {
1549
- const nextContexts = await mero.admin.listGroupContexts(groupId);
1550
- if (mountedRef.current) {
1551
- setContexts(nextContexts);
1552
- }
1553
- } catch (err) {
1554
- const errorValue = toError(err);
1555
- if (mountedRef.current) {
1556
- setError(errorValue);
1557
- }
1558
- } finally {
1559
- if (mountedRef.current) {
1560
- setLoading(false);
1561
- }
1562
- }
1563
- }, [groupId, mero, mountedRef]);
1564
- react.useEffect(() => {
1565
- void refetch();
1566
- }, [refetch]);
1567
- return { contexts, loading, error, refetch };
1529
+ const { data, loading, error, refetch } = useAsyncResource(
1530
+ mero && groupId ? () => mero.admin.listGroupContexts(groupId) : null,
1531
+ [],
1532
+ [mero, groupId]
1533
+ );
1534
+ return { contexts: data, loading, error, refetch };
1568
1535
  }
1569
1536
  function useGroupInvitations() {
1570
1537
  const { mero } = useMero();
@@ -1600,9 +1567,11 @@ function useGroupCapabilities(groupId, memberId) {
1600
1567
  const [loading, setLoading] = react.useState(false);
1601
1568
  const [error, setError] = react.useState(null);
1602
1569
  const mountedRef = useMountedRef();
1570
+ const reqRef = react.useRef(0);
1603
1571
  const refetch = react.useCallback(async () => {
1572
+ const seq = ++reqRef.current;
1604
1573
  if (!mero || !groupId || !memberId) {
1605
- if (mountedRef.current) {
1574
+ if (mountedRef.current && seq === reqRef.current) {
1606
1575
  setCapabilitiesState(null);
1607
1576
  setError(null);
1608
1577
  setLoading(false);
@@ -1615,22 +1584,27 @@ function useGroupCapabilities(groupId, memberId) {
1615
1584
  }
1616
1585
  try {
1617
1586
  const response = await mero.admin.getMemberCapabilities(groupId, memberId);
1618
- if (mountedRef.current) {
1587
+ if (mountedRef.current && seq === reqRef.current) {
1619
1588
  setCapabilitiesState(response.capabilities);
1620
1589
  }
1621
1590
  return response.capabilities;
1622
1591
  } catch (err) {
1623
1592
  const errorValue = toError(err);
1624
- if (mountedRef.current) {
1593
+ if (mountedRef.current && seq === reqRef.current) {
1625
1594
  setError(errorValue);
1626
1595
  }
1627
1596
  return null;
1628
1597
  } finally {
1629
- if (mountedRef.current) {
1598
+ if (mountedRef.current && seq === reqRef.current) {
1630
1599
  setLoading(false);
1631
1600
  }
1632
1601
  }
1633
1602
  }, [groupId, memberId, mero, mountedRef]);
1603
+ react.useEffect(() => {
1604
+ reqRef.current += 1;
1605
+ setCapabilitiesState(null);
1606
+ setError(null);
1607
+ }, [groupId, memberId]);
1634
1608
  react.useEffect(() => {
1635
1609
  void refetch();
1636
1610
  }, [refetch]);
@@ -1810,83 +1784,21 @@ function useJoinSubgroupInheritance() {
1810
1784
  }
1811
1785
  function useContextGroup(contextId) {
1812
1786
  const { mero } = useMero();
1813
- const [groupId, setGroupId] = react.useState(null);
1814
- const [loading, setLoading] = react.useState(false);
1815
- const [error, setError] = react.useState(null);
1816
- const mountedRef = useMountedRef();
1817
- const refetch = react.useCallback(async () => {
1818
- if (!mero || !contextId) {
1819
- if (mountedRef.current) {
1820
- setGroupId(null);
1821
- setError(null);
1822
- setLoading(false);
1823
- }
1824
- return;
1825
- }
1826
- if (mountedRef.current) {
1827
- setLoading(true);
1828
- setError(null);
1829
- }
1830
- try {
1831
- const result = await mero.admin.getContextGroup(contextId);
1832
- if (mountedRef.current) {
1833
- setGroupId(result);
1834
- }
1835
- } catch (err) {
1836
- const errorValue = toError(err);
1837
- if (mountedRef.current) {
1838
- setError(errorValue);
1839
- }
1840
- } finally {
1841
- if (mountedRef.current) {
1842
- setLoading(false);
1843
- }
1844
- }
1845
- }, [contextId, mero, mountedRef]);
1846
- react.useEffect(() => {
1847
- void refetch();
1848
- }, [refetch]);
1849
- return { groupId, loading, error, refetch };
1787
+ const { data, loading, error, refetch } = useAsyncResource(
1788
+ mero && contextId ? () => mero.admin.getContextGroup(contextId) : null,
1789
+ null,
1790
+ [mero, contextId]
1791
+ );
1792
+ return { groupId: data, loading, error, refetch };
1850
1793
  }
1851
1794
  function useGroupInfo(groupId) {
1852
1795
  const { mero } = useMero();
1853
- const [groupInfo, setGroupInfo] = react.useState(null);
1854
- const [loading, setLoading] = react.useState(false);
1855
- const [error, setError] = react.useState(null);
1856
- const mountedRef = useMountedRef();
1857
- const refetch = react.useCallback(async () => {
1858
- if (!mero || !groupId) {
1859
- if (mountedRef.current) {
1860
- setGroupInfo(null);
1861
- setError(null);
1862
- setLoading(false);
1863
- }
1864
- return;
1865
- }
1866
- if (mountedRef.current) {
1867
- setLoading(true);
1868
- setError(null);
1869
- }
1870
- try {
1871
- const result = await mero.admin.getGroupInfo(groupId);
1872
- if (mountedRef.current) {
1873
- setGroupInfo(result);
1874
- }
1875
- } catch (err) {
1876
- const errorValue = toError(err);
1877
- if (mountedRef.current) {
1878
- setError(errorValue);
1879
- }
1880
- } finally {
1881
- if (mountedRef.current) {
1882
- setLoading(false);
1883
- }
1884
- }
1885
- }, [groupId, mero, mountedRef]);
1886
- react.useEffect(() => {
1887
- void refetch();
1888
- }, [refetch]);
1889
- return { groupInfo, loading, error, refetch };
1796
+ const { data, loading, error, refetch } = useAsyncResource(
1797
+ mero && groupId ? () => mero.admin.getGroupInfo(groupId) : null,
1798
+ null,
1799
+ [mero, groupId]
1800
+ );
1801
+ return { groupInfo: data, loading, error, refetch };
1890
1802
  }
1891
1803
  function useDeleteGroup() {
1892
1804
  const { mero } = useMero();
@@ -1938,156 +1850,39 @@ function useRemoveGroupMembers() {
1938
1850
  }
1939
1851
  function useNamespaces() {
1940
1852
  const { mero } = useMero();
1941
- const [namespaces, setNamespaces] = react.useState([]);
1942
- const [loading, setLoading] = react.useState(false);
1943
- const [error, setError] = react.useState(null);
1944
- const mountedRef = useMountedRef();
1945
- const refetch = react.useCallback(async () => {
1946
- if (!mero) return;
1947
- if (mountedRef.current) {
1948
- setLoading(true);
1949
- setError(null);
1950
- }
1951
- try {
1952
- const result = await mero.admin.listNamespaces();
1953
- if (mountedRef.current) {
1954
- setNamespaces(result);
1955
- }
1956
- } catch (err) {
1957
- const errorValue = toError(err);
1958
- if (mountedRef.current) {
1959
- setError(errorValue);
1960
- }
1961
- } finally {
1962
- if (mountedRef.current) {
1963
- setLoading(false);
1964
- }
1965
- }
1966
- }, [mero, mountedRef]);
1967
- react.useEffect(() => {
1968
- void refetch();
1969
- }, [refetch]);
1970
- return { namespaces, loading, error, refetch };
1853
+ const { data, loading, error, refetch } = useAsyncResource(
1854
+ mero ? () => mero.admin.listNamespaces() : null,
1855
+ [],
1856
+ [mero]
1857
+ );
1858
+ return { namespaces: data, loading, error, refetch };
1971
1859
  }
1972
1860
  function useNamespace(namespaceId) {
1973
1861
  const { mero } = useMero();
1974
- const [namespace, setNamespace] = react.useState(null);
1975
- const [loading, setLoading] = react.useState(false);
1976
- const [error, setError] = react.useState(null);
1977
- const mountedRef = useMountedRef();
1978
- const refetch = react.useCallback(async () => {
1979
- if (!mero || !namespaceId) {
1980
- if (mountedRef.current) {
1981
- setNamespace(null);
1982
- setError(null);
1983
- setLoading(false);
1984
- }
1985
- return;
1986
- }
1987
- if (mountedRef.current) {
1988
- setLoading(true);
1989
- setError(null);
1990
- }
1991
- try {
1992
- const result = await mero.admin.getNamespace(namespaceId);
1993
- if (mountedRef.current) {
1994
- setNamespace(result);
1995
- }
1996
- } catch (err) {
1997
- const errorValue = toError(err);
1998
- if (mountedRef.current) {
1999
- setError(errorValue);
2000
- }
2001
- } finally {
2002
- if (mountedRef.current) {
2003
- setLoading(false);
2004
- }
2005
- }
2006
- }, [namespaceId, mero, mountedRef]);
2007
- react.useEffect(() => {
2008
- void refetch();
2009
- }, [refetch]);
2010
- return { namespace, loading, error, refetch };
1862
+ const { data, loading, error, refetch } = useAsyncResource(
1863
+ mero && namespaceId ? () => mero.admin.getNamespace(namespaceId) : null,
1864
+ null,
1865
+ [mero, namespaceId]
1866
+ );
1867
+ return { namespace: data, loading, error, refetch };
2011
1868
  }
2012
1869
  function useNamespaceIdentity(namespaceId) {
2013
1870
  const { mero } = useMero();
2014
- const [identity, setIdentity] = react.useState(null);
2015
- const [loading, setLoading] = react.useState(false);
2016
- const [error, setError] = react.useState(null);
2017
- const mountedRef = useMountedRef();
2018
- const refetch = react.useCallback(async () => {
2019
- if (!mero || !namespaceId) {
2020
- if (mountedRef.current) {
2021
- setIdentity(null);
2022
- setError(null);
2023
- setLoading(false);
2024
- }
2025
- return;
2026
- }
2027
- if (mountedRef.current) {
2028
- setLoading(true);
2029
- setError(null);
2030
- }
2031
- try {
2032
- const result = await mero.admin.getNamespaceIdentity(namespaceId);
2033
- if (mountedRef.current) {
2034
- setIdentity(result);
2035
- }
2036
- } catch (err) {
2037
- const errorValue = toError(err);
2038
- if (mountedRef.current) {
2039
- setError(errorValue);
2040
- }
2041
- } finally {
2042
- if (mountedRef.current) {
2043
- setLoading(false);
2044
- }
2045
- }
2046
- }, [namespaceId, mero, mountedRef]);
2047
- react.useEffect(() => {
2048
- void refetch();
2049
- }, [refetch]);
2050
- return { identity, loading, error, refetch };
1871
+ const { data, loading, error, refetch } = useAsyncResource(
1872
+ mero && namespaceId ? () => mero.admin.getNamespaceIdentity(namespaceId) : null,
1873
+ null,
1874
+ [mero, namespaceId]
1875
+ );
1876
+ return { identity: data, loading, error, refetch };
2051
1877
  }
2052
1878
  function useNamespacesForApplication(applicationId) {
2053
1879
  const { mero } = useMero();
2054
- const [namespaces, setNamespaces] = react.useState([]);
2055
- const [loading, setLoading] = react.useState(false);
2056
- const [error, setError] = react.useState(null);
2057
- const mountedRef = useMountedRef();
2058
- const refetch = react.useCallback(async () => {
2059
- if (!mero || !applicationId) {
2060
- if (mountedRef.current) {
2061
- setNamespaces([]);
2062
- setError(null);
2063
- setLoading(false);
2064
- }
2065
- return;
2066
- }
2067
- if (mountedRef.current) {
2068
- setLoading(true);
2069
- setError(null);
2070
- }
2071
- try {
2072
- const result = await mero.admin.listNamespacesForApplication(applicationId);
2073
- if (mountedRef.current) {
2074
- setNamespaces(result);
2075
- }
2076
- } catch (err) {
2077
- const errorValue = toError(err);
2078
- if (mountedRef.current) {
2079
- setError(errorValue);
2080
- }
2081
- } finally {
2082
- if (mountedRef.current) {
2083
- setLoading(false);
2084
- }
2085
- }
2086
- }, [applicationId, mero, mountedRef]);
2087
- react.useEffect(() => {
2088
- void refetch();
2089
- }, [refetch]);
2090
- return { namespaces, loading, error, refetch };
1880
+ const { data, loading, error, refetch } = useAsyncResource(
1881
+ mero && applicationId ? () => mero.admin.listNamespacesForApplication(applicationId) : null,
1882
+ [],
1883
+ [mero, applicationId]
1884
+ );
1885
+ return { namespaces: data, loading, error, refetch };
2091
1886
  }
2092
1887
  function useCreateNamespace() {
2093
1888
  const { mero } = useMero();
@@ -2151,43 +1946,12 @@ function useCreateGroupInNamespace() {
2151
1946
  }
2152
1947
  function useNamespaceGroups(namespaceId) {
2153
1948
  const { mero } = useMero();
2154
- const [groups, setGroups] = react.useState([]);
2155
- const [loading, setLoading] = react.useState(false);
2156
- const [error, setError] = react.useState(null);
2157
- const mountedRef = useMountedRef();
2158
- const refetch = react.useCallback(async () => {
2159
- if (!mero || !namespaceId) {
2160
- if (mountedRef.current) {
2161
- setGroups([]);
2162
- setError(null);
2163
- setLoading(false);
2164
- }
2165
- return;
2166
- }
2167
- if (mountedRef.current) {
2168
- setLoading(true);
2169
- setError(null);
2170
- }
2171
- try {
2172
- const result = await mero.admin.listNamespaceGroups(namespaceId);
2173
- if (mountedRef.current) {
2174
- setGroups(result);
2175
- }
2176
- } catch (err) {
2177
- const errorValue = toError(err);
2178
- if (mountedRef.current) {
2179
- setError(errorValue);
2180
- }
2181
- } finally {
2182
- if (mountedRef.current) {
2183
- setLoading(false);
2184
- }
2185
- }
2186
- }, [namespaceId, mero, mountedRef]);
2187
- react.useEffect(() => {
2188
- void refetch();
2189
- }, [refetch]);
2190
- return { groups, loading, error, refetch };
1949
+ const { data, loading, error, refetch } = useAsyncResource(
1950
+ mero && namespaceId ? () => mero.admin.listNamespaceGroups(namespaceId) : null,
1951
+ [],
1952
+ [mero, namespaceId]
1953
+ );
1954
+ return { groups: data, loading, error, refetch };
2191
1955
  }
2192
1956
  function useUpdateMemberRole() {
2193
1957
  const { mero } = useMero();
@@ -2227,83 +1991,21 @@ function useSetSubgroupVisibility() {
2227
1991
  }
2228
1992
  function useDefaultCapabilities(groupId) {
2229
1993
  const { mero } = useMero();
2230
- const [defaultCapabilities, setDefaultCapabilitiesState] = react.useState(null);
2231
- const [loading, setLoading] = react.useState(false);
2232
- const [error, setError] = react.useState(null);
2233
- const mountedRef = useMountedRef();
2234
- const refetch = react.useCallback(async () => {
2235
- if (!mero || !groupId) {
2236
- if (mountedRef.current) {
2237
- setDefaultCapabilitiesState(null);
2238
- setError(null);
2239
- setLoading(false);
2240
- }
2241
- return;
2242
- }
2243
- if (mountedRef.current) {
2244
- setLoading(true);
2245
- setError(null);
2246
- }
2247
- try {
2248
- const result = await mero.admin.getDefaultCapabilities(groupId);
2249
- if (mountedRef.current) {
2250
- setDefaultCapabilitiesState(result);
2251
- }
2252
- } catch (err) {
2253
- const errorValue = toError(err);
2254
- if (mountedRef.current) {
2255
- setError(errorValue);
2256
- }
2257
- } finally {
2258
- if (mountedRef.current) {
2259
- setLoading(false);
2260
- }
2261
- }
2262
- }, [groupId, mero, mountedRef]);
2263
- react.useEffect(() => {
2264
- void refetch();
2265
- }, [refetch]);
2266
- return { defaultCapabilities, loading, error, refetch };
1994
+ const { data, loading, error, refetch } = useAsyncResource(
1995
+ mero && groupId ? () => mero.admin.getDefaultCapabilities(groupId) : null,
1996
+ null,
1997
+ [mero, groupId]
1998
+ );
1999
+ return { defaultCapabilities: data, loading, error, refetch };
2267
2000
  }
2268
2001
  function useSubgroupVisibility(groupId) {
2269
2002
  const { mero } = useMero();
2270
- const [subgroupVisibility, setSubgroupVisibilityState] = react.useState(null);
2271
- const [loading, setLoading] = react.useState(false);
2272
- const [error, setError] = react.useState(null);
2273
- const mountedRef = useMountedRef();
2274
- const refetch = react.useCallback(async () => {
2275
- if (!mero || !groupId) {
2276
- if (mountedRef.current) {
2277
- setSubgroupVisibilityState(null);
2278
- setError(null);
2279
- setLoading(false);
2280
- }
2281
- return;
2282
- }
2283
- if (mountedRef.current) {
2284
- setLoading(true);
2285
- setError(null);
2286
- }
2287
- try {
2288
- const result = await mero.admin.getSubgroupVisibility(groupId);
2289
- if (mountedRef.current) {
2290
- setSubgroupVisibilityState(result);
2291
- }
2292
- } catch (err) {
2293
- const errorValue = toError(err);
2294
- if (mountedRef.current) {
2295
- setError(errorValue);
2296
- }
2297
- } finally {
2298
- if (mountedRef.current) {
2299
- setLoading(false);
2300
- }
2301
- }
2302
- }, [groupId, mero, mountedRef]);
2303
- react.useEffect(() => {
2304
- void refetch();
2305
- }, [refetch]);
2306
- return { subgroupVisibility, loading, error, refetch };
2003
+ const { data, loading, error, refetch } = useAsyncResource(
2004
+ mero && groupId ? () => mero.admin.getSubgroupVisibility(groupId) : null,
2005
+ null,
2006
+ [mero, groupId]
2007
+ );
2008
+ return { subgroupVisibility: data, loading, error, refetch };
2307
2009
  }
2308
2010
  function useSetTeeAdmissionPolicy() {
2309
2011
  const { mero } = useMero();
@@ -2367,43 +2069,12 @@ function useSetContextMetadata() {
2367
2069
  }
2368
2070
  function useGroupMetadata(groupId) {
2369
2071
  const { mero } = useMero();
2370
- const [metadata, setMetadata] = react.useState(null);
2371
- const [loading, setLoading] = react.useState(false);
2372
- const [error, setError] = react.useState(null);
2373
- const mountedRef = useMountedRef();
2374
- const refetch = react.useCallback(async () => {
2375
- if (!mero || !groupId) {
2376
- if (mountedRef.current) {
2377
- setMetadata(null);
2378
- setError(null);
2379
- setLoading(false);
2380
- }
2381
- return;
2382
- }
2383
- if (mountedRef.current) {
2384
- setLoading(true);
2385
- setError(null);
2386
- }
2387
- try {
2388
- const result = await mero.admin.getGroupMetadata(groupId);
2389
- if (mountedRef.current) {
2390
- setMetadata(result);
2391
- }
2392
- } catch (err) {
2393
- const errorValue = toError(err);
2394
- if (mountedRef.current) {
2395
- setError(errorValue);
2396
- }
2397
- } finally {
2398
- if (mountedRef.current) {
2399
- setLoading(false);
2400
- }
2401
- }
2402
- }, [groupId, mero, mountedRef]);
2403
- react.useEffect(() => {
2404
- void refetch();
2405
- }, [refetch]);
2406
- return { metadata, loading, error, refetch };
2072
+ const { data, loading, error, refetch } = useAsyncResource(
2073
+ mero && groupId ? () => mero.admin.getGroupMetadata(groupId) : null,
2074
+ null,
2075
+ [mero, groupId]
2076
+ );
2077
+ return { metadata: data, loading, error, refetch };
2407
2078
  }
2408
2079
  function useMemberMetadata(groupId, identity) {
2409
2080
  const { mero } = useMero();
@@ -2557,43 +2228,12 @@ function useReparentGroup() {
2557
2228
  }
2558
2229
  function useSubgroups(groupId) {
2559
2230
  const { mero } = useMero();
2560
- const [subgroups, setSubgroups] = react.useState([]);
2561
- const [loading, setLoading] = react.useState(false);
2562
- const [error, setError] = react.useState(null);
2563
- const mountedRef = useMountedRef();
2564
- const refetch = react.useCallback(async () => {
2565
- if (!mero || !groupId) {
2566
- if (mountedRef.current) {
2567
- setSubgroups([]);
2568
- setError(null);
2569
- setLoading(false);
2570
- }
2571
- return;
2572
- }
2573
- if (mountedRef.current) {
2574
- setLoading(true);
2575
- setError(null);
2576
- }
2577
- try {
2578
- const result = await mero.admin.listSubgroups(groupId);
2579
- if (mountedRef.current) {
2580
- setSubgroups(result);
2581
- }
2582
- } catch (err) {
2583
- const errorValue = toError(err);
2584
- if (mountedRef.current) {
2585
- setError(errorValue);
2586
- }
2587
- } finally {
2588
- if (mountedRef.current) {
2589
- setLoading(false);
2590
- }
2591
- }
2592
- }, [groupId, mero, mountedRef]);
2593
- react.useEffect(() => {
2594
- void refetch();
2595
- }, [refetch]);
2596
- return { subgroups, loading, error, refetch };
2231
+ const { data, loading, error, refetch } = useAsyncResource(
2232
+ mero && groupId ? () => mero.admin.listSubgroups(groupId) : null,
2233
+ [],
2234
+ [mero, groupId]
2235
+ );
2236
+ return { subgroups: data, loading, error, refetch };
2597
2237
  }
2598
2238
  function useDetachContextFromGroup() {
2599
2239
  const { mero } = useMero();