@proca/widget
Version:
Proca is an open-source campaign toolkit designed to empower activists and organisations in their digital advocacy efforts. It provides a flexible and customisable platform for creating and managing online petitions, email campaigns, and other forms of di
408 lines (387 loc) • 11.5 kB
JavaScript
import React, { useState, useEffect, useCallback, Fragment } from "react";
import TwitterList from "@components/twitter/List";
import { tweet } from "@components/twitter/Action";
import Dialog from "@components/Dialog";
import ProcaAlert from "@components/Alert";
import { Alert } from "@material-ui/lab";
import Country from "@components/field/Country";
import useData from "@hooks/useData";
import Register from "@components/Register";
import Message from "@components/twitter/Message";
import { useTranslation } from "react-i18next";
import { useCampaignConfig } from "@hooks/useConfig";
import { useForm } from "react-hook-form";
import { pickOne, tokenize } from "@lib/text";
import { Grid, Button } from "@material-ui/core";
import TwitterIcon from "../images/Twitter.js";
import Again, { Next } from "@components/twitter/Again";
import { SvgIcon } from "@material-ui/core";
import { sample } from "@lib/array";
import ReloadIcon from "@material-ui/icons/Cached";
import { makeStyles } from "@material-ui/core/styles";
import get from "lodash/get";
import PreviousStepConfirm from "@components/layout/PreviousStepConfirm";
//TODO should be moved to widget and change logic
const useStyles = makeStyles(theme => ({
skip: {
marginTop: theme.spacing(1),
},
media: {
width: "100%",
},
}));
const Intro = props => {
const { t } = useTranslation();
const config = useCampaignConfig();
console.log(config.component.twitter);
if (
config.component.twitter &&
config.component.twitter.filter &&
!config.component.twitter.filter.includes("random")
)
return null;
if (props.total === 0) {
return <p>Selecting your target...</p>;
}
return (
<Grid container alignItems="flex-start">
<Grid item xs={8}>
<p>
{t("target.random", {
total: props.total,
count: config.component.twitter?.sample || 1,
})}
</p>
</Grid>
<Grid item xs={4}>
<Button
variant="contained"
startIcon={<ReloadIcon />}
onClick={props.handleClick}
>
{t("Another")}
</Button>
</Grid>
</Grid>
);
};
const TweetButton = props => {
const { t } = useTranslation();
const config = useCampaignConfig();
const classes = useStyles();
const handleClick = e => {
props.handleClick(e);
// if (!config.component.twitter?.filter?.includes("random")) {
// props.done(e);
// }
};
return (
<>
<Grid item xs={12}>
<Button
color="primary"
variant="contained"
fullWidth
onClick={handleClick}
size="large"
endIcon={
<SvgIcon>
<TwitterIcon />
</SvgIcon>
}
>
{t(config.component.tweet?.button || "Tweet")}
</Button>
</Grid>
{config.component.twitter?.skip && (
<Grid item xs={12} className={classes.skip}>
<Next done={props.done} />
</Grid>
)}
</>
);
};
const Component = props => {
const { t } = useTranslation();
const config = useCampaignConfig();
const [profiles, setProfiles] = useState([]);
const [data, setData] = useData();
const [allProfiles, setAllProfiles] = useState(data.targets || []);
const [tweeting, setTweeting] = useState(false);
const [dialog, viewDialog] = useState(false);
const hash = data.hash || config.component.twitter?.hash;
const sampleSize = config.component.twitter?.sample || 1;
const form = useForm({
defaultValues: {
...data,
message: "",
},
});
const { watch, setValue } = form;
const country = watch("country");
let actionUrl = props.actionUrl || data?.actionUrl; // || window.location.href;
if (hash) {
// it has a picture
actionUrl = `${config.component.twitter?.metaproxy || "https://w.proca.app"}/${config.campaign.name}/${hash}?url=${encodeURIComponent(document.location.origin + document.location.pathname)}`;
} else {
if (!actionUrl && config.component.twitter?.actionUrl !== false) {
actionUrl = window.location;
}
}
const setMessage = useCallback(
profile => {
if (config.component.twitter?.multilingual && profile[0].locale) {
const locale = profile[0].locale;
const source =
(config.component.twitter?.data &&
data[config.component.twitter.data][locale]) ||
{};
const msg = get(
source,
config.component.twitter?.key || "campaign:twitter.message"
);
if (msg) {
setValue(
"message",
tokenize(pickOne(msg), { profile: profile, url: actionUrl })
);
return;
}
if (!msg && data.twitter) {
setValue(
"message",
tokenize(pickOne(data.twitter), {
profile: profile,
url: actionUrl,
})
);
return;
}
}
setValue(
"message",
tokenize(
pickOne(
data.twitter ||
t(["campaign:twitter.message", "campaign:share.twitter"])
),
{ profile: profile, url: actionUrl }
)
);
},
[
config.component.twitter?.data,
config.component.twitter?.key,
config.component.twitter?.multilingual,
data,
setValue,
t,
]
);
const filterRandomProfile = useCallback(() => {
const d = sample(allProfiles, sampleSize);
setMessage(d);
setProfiles(() => {
return d;
});
}, [allProfiles, setMessage]);
const randomize = config.component.twitter?.filter
? config.component.twitter?.filter?.includes("random")
: true;
useEffect(() => {
if (!randomize) return;
if (allProfiles.length < 2) return;
filterRandomProfile();
}, [randomize, allProfiles, filterRandomProfile]);
const handleTweet = () => {
tweet({
actionPage: config.actionPage,
message: form.getValues("message"),
screen_name: profiles.map(d => d.screen_name).join(" @"),
actionUrl: actionUrl,
});
const target = data.targets ? data.targets.concat(profiles) : profiles;
setTweeting(true);
setData("targets", target);
};
const url =
config.component.twitter?.listUrl === true ||
!config.component.twitter?.listUrl
? `https://widget.proca.app/t/${config.campaign.name}.json`
: config.component.twitter.listUrl;
useEffect(() => {
const fetchData = async url => {
await fetch(url)
.then(res => {
if (!res.ok) throw res.error();
return res.json();
})
.then(targets => {
if (
config.hook &&
typeof config.hook["twitter:load"] === "function"
) {
config.hook["twitter:load"](targets);
}
let d = targets.filter(
c => c.screen_name && c.screen_name.length > 0
);
d.forEach(c => {
if (c.country) c.country = c.country.toLowerCase();
});
// if the country of the visitor is set, filter the list of targets
if (country) {
const country2l = country.toLowerCase();
const filtered = d.filter(c => c.country === country2l);
if (filtered.length > 0) d = filtered;
}
setAllProfiles(d);
// filterRandom(d);
})
.catch(error => {
console.log(error);
});
};
if (data.targets) {
const d = data.targets.filter(
c => c.screen_name && c.screen_name.length > 0
);
setAllProfiles(d);
// filterRandom(d);
} else {
fetchData(url);
}
}, [
data.targets,
url,
country,
setValue,
setMessage,
config.campaign.name,
config.component,
config.hook,
t,
]);
const filterProfiles = useCallback(
country => {
// setProfiles(allProfiles);
if (!country) return;
country = country.toLowerCase();
const profiles = allProfiles.filter(d => {
return (
d.country === country ||
(d.country === "") | (d.constituency?.country === country)
);
});
console.warn("do we filter profile?", profiles.length);
//setProfiles(profiles);
},
[allProfiles]
);
useEffect(() => {
// setFilter({country:config.country});
filterProfiles(country);
/* if (typeof config.hook["twitter:load"] === "function") {
let d = allProfiles;
config.hook["twitter:load"](d);
setProfiles(d);
}*/
}, [country, filterProfiles]);
/*
useEffect(() => {
// setFilter({country:config.country});
filterProfiles(country);
}, [country, filterProfiles]);
*/
const handleDone = () => {
if (config.component.twitter?.anonymous === true) return;
if (!data.firstname) viewDialog(true);
};
const handleClose = () => {
viewDialog(false);
};
console.log("filter", props.country, config.component.twitter?.filter);
const FirstStep = props => {
return (
<>
<PreviousStepConfirm email={config.component.consent?.email} />
{config.component.twitter?.filter?.includes("country") && (
<Country form={form} list={config.component?.twitter?.countries} />
)}
<Intro total={allProfiles.length} handleClick={filterRandomProfile} />
<TwitterList
profiles={profiles}
actionPage={props.actionPage}
actionUrl={actionUrl}
form={form}
clickable={config.component.twitter?.clickable}
done={handleDone}
/>
<Message form={form} />
{hash && <ShowCard hash={hash} />}
<TweetButton handleClick={handleTweet} done={props.done} />
</>
);
};
const ShowCard = props => {
const classes = useStyles();
const image = `${process.env.REACT_APP_SUPABASE_URL}/storage/v1/object/public/picture/${config.campaign.name}/${props.hash}.jpg`;
return (
<img
src={image}
alt="generated by the supporter"
className={classes.media}
/>
);
};
// "addLink": true,
// "showCard": true
const SecondStep = () => {
if (!tweeting) return null;
if (
profiles.length === allProfiles.length &&
!config.component.twitter?.filter?.includes("random")
) {
return (
<>
<Alert severity="info">{t("twitter.instruction")}</Alert>
<Next done={props.done} />
</>
);
}
return (
<>
<Again
again={() => {
filterRandomProfile();
setTweeting(false);
}}
done={props.done}
/>
<ProcaAlert severity="info">
{t(
"twitter.instruction",
"Please complete sending the tweet in the new window (on twitter.com)"
)}
</ProcaAlert>
</>
);
};
return (
<Fragment>
<Dialog
dialog={dialog}
actionPage={props.actionPage}
close={handleClose}
content={Register}
buttonText={config.param.register}
name={config.param.dialogTitle || t("dialogTitle")}
>
<Register actionPage={props.actionPage} done={props.done} />
</Dialog>
{!tweeting && <FirstStep done={props.done} profiles={profiles} />}
{tweeting && <SecondStep done={props.done} />}
</Fragment>
);
};
export default Component;