Skip to content

Commit

Permalink
Merge pull request #296 from heshammourad/feature/content-db
Browse files Browse the repository at this point in the history
Add static content component
  • Loading branch information
heshammourad authored Aug 26, 2024
2 parents d8c1d7b + d52c581 commit 22b9959
Show file tree
Hide file tree
Showing 17 changed files with 130 additions and 36 deletions.
12 changes: 6 additions & 6 deletions react-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 2 additions & 7 deletions react-ui/src/components/EntryDescriptionDrawer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ import Countdown from './Countdown';
import DrawerSectionHeader from './DrawerSectionHeader';
import FiveStar from './FiveStar';
import FmpIcon from './FmpIcon';
import HtmlWrapper from './HtmlWrapper';
import FormattedContent from './FormattedContent';
import ListItemButton from './ListItemButton';
import RedditMarkdown from './RedditMarkdown';
import RedditUserAttribution from './RedditUserAttribution';
import VotingSlider from './VotingSlider';

Expand Down Expand Up @@ -149,11 +148,7 @@ function EntryDescriptionDrawer({ entryId }) {
</Box>
)}
<DrawerSectionHeader>Description</DrawerSectionHeader>
{markdown ? (
<RedditMarkdown text={description} />
) : (
<HtmlWrapper html={description} />
)}
<FormattedContent content={description} markdown={markdown} />
<DrawerSectionHeader>Links</DrawerSectionHeader>
<List>
{!localVoting && (
Expand Down
25 changes: 25 additions & 0 deletions react-ui/src/components/FormattedContent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import PropTypes from 'prop-types';

import HtmlWrapper from './HtmlWrapper';
import RedditMarkdown from './RedditMarkdown';

function FormattedContent({ className, content, markdown }) {
return markdown ? (
<RedditMarkdown {...{ className, text: content }} />
) : (
<HtmlWrapper {...{ className, html: content }} />
);
}

FormattedContent.propTypes = {
className: PropTypes.string,
content: PropTypes.string.isRequired,
markdown: PropTypes.bool,
};

FormattedContent.defaultProps = {
className: '',
markdown: false,
};

export default FormattedContent;
3 changes: 0 additions & 3 deletions react-ui/src/components/HtmlWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ HtmlWrapper.propTypes = {

HtmlWrapper.defaultProps = {
className: undefined,
};

HtmlWrapper.defaultProps = {
html: '',
};

Expand Down
33 changes: 33 additions & 0 deletions react-ui/src/components/StaticContent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import PropTypes from 'prop-types';

import useSwrStaticContent from '../data/useSwrStaticContent';

import FormattedContent from './FormattedContent';

/**
* Renders static content from Firebase.
* @param props
* @param {string} [props.className] - Additional classes to apply.
* @param {string} props.id - DB ID of static content.
*/
function StaticContent({ className, id }) {
const { data } = useSwrStaticContent(id);
if (!data) {
return null;
}

const { content, markdown } = data;

return <FormattedContent {...{ className, content, markdown }} />;
}

StaticContent.propTypes = {
className: PropTypes.string,
id: PropTypes.string.isRequired,
};

StaticContent.defaultProps = {
className: undefined,
};

export default StaticContent;
4 changes: 2 additions & 2 deletions react-ui/src/components/SubmissionRow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { putData } from '../data/api';
import useSwrMutation from '../data/useSwrMutation';

import Fieldset from './Fieldset';
import RedditMarkdown from './RedditMarkdown';
import FormattedContent from './FormattedContent';
import RedditUserAttribution from './RedditUserAttribution';
import SpinnerButton from './SpinnerButton';

Expand Down Expand Up @@ -381,7 +381,7 @@ function SubmissionRow({
Description
</Typography>
<div className={classes.description}>
<RedditMarkdown text={description} />
<FormattedContent content={description} markdown />
</div>
</div>
{!moderator && submissionRejected && (
Expand Down
4 changes: 2 additions & 2 deletions react-ui/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ export { default as Fieldset } from './Fieldset';
export { default as FilterChip } from './FilterChip';
export { default as FiveStar } from './FiveStar';
export { default as FmpIcon } from './FmpIcon';
export { default as FormattedContent } from './FormattedContent';
export { default as Header } from './Header';
export { default as HtmlWrapper } from './HtmlWrapper';
export { default as InternalLink } from './InternalLink';
export { default as LazyLoadCardImage } from './LazyLoadCardImage';
export { default as ListItemButton } from './ListItemButton';
Expand All @@ -30,9 +30,9 @@ export { default as PageContainer } from './PageContainer';
export { default as PageWithDrawer } from './PageWithDrawer';
export { default as ProtectedRoute } from './ProtectedRoute';
export { default as RedditLogInDialog } from './RedditLogInDialog';
export { default as RedditMarkdown } from './RedditMarkdown';
export { default as RedditUserAttribution } from './RedditUserAttribution';
export { default as SpinnerButton } from './SpinnerButton';
export { default as StaticContent } from './StaticContent';
export { default as SubmissionsTable } from './SubmissionsTable';
export { default as TabPanel } from './TabPanel';
export { default as VotingSlider } from './VotingSlider';
5 changes: 5 additions & 0 deletions react-ui/src/data/useSwrStaticContent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import useSwrAuth from './useSwrAuth';

const useSwrStaticContent = (id) => useSwrAuth(`/staticContent/${id}`);

export default useSwrStaticContent;
8 changes: 4 additions & 4 deletions react-ui/src/pages/contest/Contest.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import { animateScroll } from 'react-scroll';

import {
EntryDescriptionDrawer,
HtmlWrapper,
PageContainer,
PageWithDrawer,
RedditLogInDialog,
StaticContent,
} from '../../components';
import useSwrContest from '../../data/useSwrContest';

Expand Down Expand Up @@ -165,7 +165,7 @@ function Contest() {
const { headingVariant } = useContestSizing();

const {
categories, isContestMode, name, subtext, votingWindowOpen, winners,
categories, isContestMode, name, votingWindowOpen, winners,
} = contest;

return (
Expand Down Expand Up @@ -203,10 +203,10 @@ function Contest() {
{votingWindowOpen === false && (
<ContestUnderReview {...{ isValidating, mutate }} />
)}
{isContestMode && subtext && (
{isContestMode && (
<Box marginBottom={3}>
<Typography component="div" variant="subtitle1">
<HtmlWrapper html={subtext} />
<StaticContent id="voting_instructions" />
</Typography>
</Box>
)}
Expand Down
2 changes: 1 addition & 1 deletion react-ui/src/pages/contest/ContestAppBarMain.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Box from '@material-ui/core/Box';
import PropTypes from 'prop-types';
import { useLocation } from 'react-router-dom';

import { RouterLinkIconButton, Countdown } from '../../components';
import { Countdown, RouterLinkIconButton } from '../../components';
import useVotingStatus from '../../data/useVotingStatus';

export default function ContestAppBarMain({ handleReload, contest }) {
Expand Down
8 changes: 2 additions & 6 deletions react-ui/src/pages/hallOfFame/HallOfFameCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { useState } from 'react';
import {
CustomIconButton,
ExternalLink,
HtmlWrapper,
FormattedContent,
LazyLoadCardImage,
RedditMarkdown,
RedditUserAttribution,
Expand Down Expand Up @@ -184,11 +184,7 @@ function HallOfFameCard({
component="div"
variant="caption"
>
{markdown ? (
<RedditMarkdown text={description} />
) : (
<HtmlWrapper html={description} />
)}
<FormattedContent content={description} markdown={markdown} />
</Typography>
</Collapse>
</Card>
Expand Down
7 changes: 4 additions & 3 deletions react-ui/src/pages/submission/SubmissionForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
ExternalLink,
Fieldset,
ProtectedRoute,
RedditMarkdown,
FormattedContent,
SpinnerButton,
} from '../../components';
import { postData } from '../../data/api';
Expand Down Expand Up @@ -563,11 +563,12 @@ function SubmissionForm({
onChange={handleFieldChange}
inputProps={{ maxLength: CHAR_LIMIT_DESCRIPTION }}
/>
<RedditMarkdown
<FormattedContent
className={clsx(classes.descriptionPreview, {
[classes.descriptionEntry]: !previewDescription,
})}
text={formState.description.value}
content={formState.description.value}
markdown
/>
</div>
<Button
Expand Down
4 changes: 2 additions & 2 deletions react-ui/src/pages/submission/SubmissionPrompt.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
import PropTypes from 'prop-types';

import { RedditMarkdown } from '../../components';
import { FormattedContent } from '../../components';

import May23 from './content/May23';

Expand All @@ -14,7 +14,7 @@ function SubmissionPrompt({ contestId, prompt }) {
if (!prompt) {
return null;
}
return <RedditMarkdown text={prompt} />;
return <FormattedContent content={prompt} markdown />;
}

export default SubmissionPrompt;
Expand Down
31 changes: 31 additions & 0 deletions server/api/staticContent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const db = require('../db');
const { createLogger } = require('../logger');

const logger = createLogger('API/STATIC_CONTENT');

/**
* Get static content from Firebase.
*
* @param {Object} req - Express request
* @param {Object} req.params - Parameters on request
* @param {string} req.params.id - DB id of static content to fetch
* @param {*} res - Express response
*/
exports.get = async ({ params: { id } }, res) => {
try {
const [result = {}] = await db.select(
'SELECT content, markdown FROM static_content WHERE id = $1',
[id],
);
const { content, markdown } = result;
if (!content) {
logger.info(`Static content with id='${id}' not found`);
res.status(404).send();
}

res.send({ content, markdown });
} catch (err) {
logger.warn(`Error getting /${id}: ${err}`);
res.status(500).send();
}
};
2 changes: 2 additions & 0 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const init = require('./api/init');
const reviewSubmissions = require('./api/reviewSubmissions');
const revokeToken = require('./api/revokeToken');
const settings = require('./api/settings');
const staticContent = require('./api/staticContent');
const submission = require('./api/submission');
const { checkRequiredFields } = require('./api/validation');
const votes = require('./api/votes');
Expand Down Expand Up @@ -132,6 +133,7 @@ if (!IS_DEV && cluster.isMaster) {
.all(requireAuthentication)
.get(settings.get)
.put(settings.put);
apiRouter.get('/staticContent/:id', staticContent.get);
apiRouter
.route('/submission')
.get(processUser(false), submission.get)
Expand Down
3 changes: 3 additions & 0 deletions static_content/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The files in this directory are copies of the files that are stored in the static_content table in
the database, placed here for reference. Best effort should be made to keep them in sync, but the
database is the source of truth.
6 changes: 6 additions & 0 deletions static_content/voting_instructions.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<ul>
<li>Go through the submissions, and <strong>rate flags from 0-5</strong>. Feel encouraged to rate them all!</li>
<li>A 0 would be a flag you think really misses the prompt or isn’t well executed, and a 5 is the best of the best.</li>
<li>Vote on a <strong>good flag</strong>, not just a good image. Review the author’s description to understand their design. Click on a flag to view the description in the info panel.</li>
<li><strong>Anonymity is key</strong> so revealing your flag while the contest is in session will result in a disqualification. After voting is over, anyone may claim their flags and we will announce the top 20 and update the <a href="http://www.reddit.com/r/vexillology/wiki/contests">yearly standings</a>.</li>
</ul>

0 comments on commit 22b9959

Please sign in to comment.