Skip to content

Commit

Permalink
chore: improve component separation of concerns, hooks, purity
Browse files Browse the repository at this point in the history
  • Loading branch information
drewbo committed Oct 23, 2024
1 parent cd4f911 commit b2d2ae5
Show file tree
Hide file tree
Showing 21 changed files with 873 additions and 722 deletions.
21 changes: 21 additions & 0 deletions frontend/hooks/useOrganizationRoles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* eslint-disable import/prefer-default-export */
import { useEffect, useState } from 'react';
import api from '../util/federalistApi';

const initState = {
orgRoles: null,
isLoading: true,
};

export const useOrganizationRoles = () => {
const [state, setState] = useState(initState);

useEffect(() => {
api.fetchOrganizationRoles().then(data => setState({
isLoading: false,
orgRoles: data,
}));
}, []);

return state;
};
214 changes: 2 additions & 212 deletions frontend/pages/customDomains/List.jsx
Original file line number Diff line number Diff line change
@@ -1,221 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { Link, useParams, useNavigate } from 'react-router-dom';
import { Link, useParams } from 'react-router-dom';
import { currentSite } from '@selectors/site';
import UsaIcon from '@shared/UsaIcon';
import { useSiteDomains } from '@hooks';
import { capitalize } from '@util';

function ListRow({ children, justify = 'flex-start', ...props }) {
return (
<div
style={{
alignItems: 'center',
display: 'flex',
justifyContent: justify,
gap: '10px',
width: '100%',
...props,
}}
>
{children}
</div>
);
}

ListRow.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
justify: PropTypes.string,
};

ListRow.defaultProps = {
justify: 'flex-start',
};

function ContextTitle({ context }) {
return (
<div style={{ display: 'inline-block' }}>
<h4 className="font-sans-lg margin-0">
{context === 'site' ? 'Live Site' : `${capitalize(context)} Site`}
</h4>
</div>
);
}

ContextTitle.propTypes = {
context: PropTypes.string.isRequired,
};

const getStateColor = (state) => {
switch (state) {
case 'provisioned':
return 'rgb(12, 175, 0)';
case 'failed':
return '#d83731';
case 'pending':
return '#112e51';
default:
return '#e27600';
}
};

function StateIndicator({ state }) {
return (
<div
className="usa-tag usa-tag--big radius-pill font-body-2xs text-ls-1"
style={{
backgroundColor: getStateColor(state),
}}
>
{state}
</div>
);
}

StateIndicator.propTypes = {
state: PropTypes.string.isRequired,
};

function DomainLink({ domain }) {
return (
<a
target="_blank"
rel="noopener noreferrer"
title={`Link to site's domain ${domain}`}
href={`https://${domain}`}
>
{domain}
</a>
);
}

DomainLink.propTypes = {
domain: PropTypes.string.isRequired,
};

function Domains({ siteId, domains, handleDelete }) {
const navigate = useNavigate();
return (
<div className="well-gray-lightest grid-row">
{domains.error && (
<div className="well grid-col-12">
<h3>
An error occurred while loading your site branch configurations.
</h3>
<p>{domains.error}</p>
</div>
)}
{!domains.isLoading && !domains.error && domains.data && (
<ul className="usa-card-group grid-col-12">
{domains.data.map((domain) => {
const sbc = domain.SiteBranchConfig;
const names = domain.names.split(',');
const actionsDisabled = domain.state !== 'pending';

return (
<li className="usa-card grid-col-12" key={`domain-${domain.id}`}>
<div className="usa-card__container bg-base-lightest">
<div className="usa-card__header">
<ListRow>
<ContextTitle context={sbc.context} branch={sbc.branch} />
<StateIndicator state={domain.state} />
</ListRow>
</div>
<div className="usa-card__body">
<ListRow>
<span style={{ fontWeight: 'bold' }}>Branch:</span>
{sbc.branch}
</ListRow>
<ListRow>
<span style={{ fontWeight: 'bold' }}>
{names.length > 1 ? 'Domains' : 'Domain'}
:
</span>
{names.map((name, idx) => (
<span key={`domain-name-${name}`}>
{domain.state === 'provisioned' ? (
<DomainLink domain={name} />
) : (
name
)}
{names.length > idx + 1 && ' '}
</span>
))}
</ListRow>
</div>
<div className="usa-card__footer">
<ListRow id="domain-edit-delete-actions" justify="flex-end">
<button
disabled={actionsDisabled}
className="usa-button"
onClick={() => navigate(
`/sites/${siteId}/custom-domains/${domain.id}/edit`
)}
alt={`Edit site domain ${domain.names}`}
type="button"
>
Edit
</button>
<button
disabled={actionsDisabled}
className="usa-button usa-button--secondary"
onClick={() => handleDelete(domain.id)}
alt={`Delete site domain ${domain.names}`}
type="button"
>
Delete
</button>
</ListRow>
{actionsDisabled && (
<ListRow justify="flex-end">
<p className="margin-bottom-0">
<em htmlFor="domain-edit-delete-actions">
*Cannot edit or delete a
{' '}
{domain.state}
{' '}
domain.
</em>
</p>
</ListRow>
)}
</div>
</div>
</li>
);
})}
</ul>
)}
{!domains.isLoading && !domains.error && domains?.data?.length === 0 && (
<p>There are no custom domains configured for this site currently.</p>
)}
</div>
);
}

Domains.propTypes = {
domains: PropTypes.shape({
isLoading: PropTypes.bool.isRequired,
error: PropTypes.string,
data: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number,
names: PropTypes.string,
state: PropTypes.string,
SiteBranchConfig: PropTypes.shape({
branch: PropTypes.string,
context: PropTypes.string,
}),
})
),
}).isRequired,
handleDelete: PropTypes.func.isRequired,
siteId: PropTypes.number.isRequired,
};
import Domains from './components/Domains';

function DomainList() {
const { id } = useParams();
Expand Down
17 changes: 17 additions & 0 deletions frontend/pages/customDomains/components/ContextTitle.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import PropTypes from 'prop-types';
import { capitalize } from '@util';

export default function ContextTitle({ context }) {
return (
<div style={{ display: 'inline-block' }}>
<h4 className="font-sans-lg margin-0">
{context === 'site' ? 'Live Site' : `${capitalize(context)} Site`}
</h4>
</div>
);
}

ContextTitle.propTypes = {
context: PropTypes.string.isRequired,
};
19 changes: 19 additions & 0 deletions frontend/pages/customDomains/components/DomainLink.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';

function DomainLink({ domain }) {
return (
<a
target="_blank"
rel="noopener noreferrer"
title={`Link to site's domain ${domain}`}
href={`https://${domain}`}
>
{domain}
</a>
);
}

DomainLink.propTypes = {
domain: PropTypes.string.isRequired,
};
Loading

0 comments on commit b2d2ae5

Please sign in to comment.