| 6 | "": "const Container = styled.div`\\\\n width: 100%;\\\\n display: flex;\\\\n flex-direction: column;\\\\n align-items: center;\\\\n margin-bottom: 30px;\\\\n`;\\\\n\\\\nconst SelectContainer = styled.div`\\\\n align-items: center;\\\\n display: flex;\\\\n flex-direction: row;\\\\n justify-content: space-between;\\\\n gap: 1rem;\\\\n width: 100%;\\\\n`;\\\\n\\\\nconst Title = styled.div`\\\\n color: #1b1b18;\\\\n font-style: normal;\\\\n font-weight: 700;\\\\n line-height: normal;\\\\n text-wrap: nowrap;\\\\n font-size: 24px;\\\\n\\\\n @media screen and (max-width: 768px) {\\\\n font-size: 22px;\\\\n }\\\\n`;\\\\n\\\\nconst Filters = styled.div`\\\\n display: flex;\\\\n gap: 1rem;\\\\n\\\\n @media screen and (max-width: 768px) {\\\\n gap: 0.5rem;\\\\n }\\\\n\\\\n .wrapper {\\\\n position: relative;\\\\n display: flex;\\\\n justify-content: flex-end;\\\\n width: 300px;\\\\n\\\\n &.mobile {\\\\n display: none;\\\\n width: 50px;\\\\n\\\\n @media screen and (max-width: 768px) {\\\\n display: flex;\\\\n }\\\\n }\\\\n\\\\n @media screen and (max-width: 768px) {\\\\n display: none;\\\\n }\\\\n\\\\n .value {\\\\n display: flex;\\\\n color: #3f3f3f;\\\\n font-size: 16px;\\\\n font-style: normal;\\\\n font-weight: 350;\\\\n line-height: 16px;\\\\n width: 100%;\\\\n height: 46px;\\\\n padding: 0px 14px;\\\\n align-items: center;\\\\n border-radius: 100px;\\\\n border: 1px solid #e3e3e0;\\\\n background: var(--NEAR-Primary-Colors-White, #fff);\\\\n }\\\\n\\\\n .icon {\\\\n position: absolute;\\\\n top: 14px;\\\\n right: 20px;\\\\n z-index: 1001;\\\\n display: flex;\\\\n\\\\n @media screen and (max-width: 768px) {\\\\n top: 0;\\\\n right: 0;\\\\n width: 40px;\\\\n height: 40px;\\\\n align-items: center;\\\\n justify-content: center;\\\\n border-radius: 50%;\\\\n border: 1px solid #e3e3e0;\\\\n }\\\\n }\\\\n }\\\\n`;\\\\n\\\\nconst ChartContainer = styled.div`\\\\n display: flex;\\\\n width: 100%;\\\\n justify-content: space-between;\\\\n align-items: center;\\\\n gap: 3rem;\\\\n\\\\n @media screen and (max-width: 1188px) {\\\\n justify-content: center;\\\\n flex-wrap: wrap;\\\\n gap: 2rem;\\\\n }\\\\n`;\\\\n\\\\nconst DesktopPicker = styled.div`\\\\n display: flex;\\\\n\\\\n @media screen and (max-width: 1188px) {\\\\n display: none;\\\\n }\\\\n`;\\\\n\\\\nconst MobilePicker = styled.div`\\\\n display: none;\\\\n\\\\n @media screen and (max-width: 1188px) {\\\\n display: flex;\\\\n }\\\\n`;\\\\n\\\\nconst { contractName } = VM.require(`ndcdev.near/widget/dashboard.Config`);\\\\n\\\\nconst defaultDAOOption = \\\\\\\"All DAOs\\\\\\\";\\\\nconst dailyTotal = { labels: [], data: [] };\\\\nconst dailyTotalUsers = { labels: [], data: [] };\\\\nconst today = new Date();\\\\nconst [loading, setLoading] = useState(false);\\\\nconst [period, setPeriod] = useState([\\\\n new Date(),\\\\n new Date(today.setMonth(today.getMonth() - 1)),\\\\n]);\\\\nconst [showDatePicker, setShowDatePicker] = useState(false);\\\\nconst [dateRange, setDateRange] = useState(\\\\\\\"\\\\\\\");\\\\nconst [selectedDAOs, setSelectedDAOs] = useState([]);\\\\nconst [dashboardView, setDashboardView] = useState(\\\\\\\"Table\\\\\\\");\\\\nconst [mobile, setMobile] = useState(false);\\\\nconst [dataState, setDataState] = useState({\\\\n totalTx: 0,\\\\n totalAccounts: 0,\\\\n uniqueAccounts: 0,\\\\n totalBalance: 0,\\\\n distributed: 0,\\\\n dailyStats: [],\\\\n});\\\\n\\\\nconst baseUrl = \\\\\\\"https://dashboard.chatme.page\\\\\\\";\\\\nconst Loading = () => <Widget src=\\\\\\\"flashui.near/widget/Loading\\\\\\\" />;\\\\n\\\\nconst get = async (url) => {\\\\n try {\\\\n return asyncFetch(`${baseUrl}/${url}`, {\\\\n method: \\\\\\\"GET\\\\\\\",\\\\n headers: {\\\\n \\\\\\\"Content-Type\\\\\\\": \\\\\\\"application/json\\\\\\\",\\\\n },\\\\n });\\\\n } catch (e) {\\\\n console.log(e);\\\\n }\\\\n};\\\\n\\\\nif (!contractName) return <Loading />;\\\\n\\\\nconst daos = Near.view(contractName, \\\\\\\"get_dao_list\\\\\\\");\\\\nif (!daos) return <Loading />;\\\\n\\\\nconst formatDate = () => {\\\\n const fmt = (date) => {\\\\n const year = date.getFullYear();\\\\n const month = (date.getMonth() + 1).toString().padStart(2, \\\\\\\"0\\\\\\\");\\\\n const day = date.getDate().toString().padStart(2, \\\\\\\"0\\\\\\\");\\\\n\\\\n return { year, month, day };\\\\n };\\\\n\\\\n const startDate = `${fmt(period[0]).year}-${fmt(period[0]).month}-${\\\\n fmt(period[0]).day\\\\n }`;\\\\n const endDate = `${fmt(period[1]).year}-${fmt(period[1]).month}-${\\\\n fmt(period[1]).day\\\\n }`;\\\\n\\\\n setDateRange(`start_date=${startDate}&end_date=${endDate}`);\\\\n\\\\n return { startDate, endDate };\\\\n};\\\\n\\\\nconst API = {\\\\n getTotal: () =>\\\\n get(`api/total?${dateRange}&&dao_list=[${daos.map((d) => d.id)}]`),\\\\n getDailyStats: () =>\\\\n get(`api/daily-stats?${dateRange}&&dao_list=[${daos.map((d) => d.id)}]`),\\\\n userRetentions: (daos) =>\\\\n get(`api/user-retention?${dateRange}&dao_list=[${daos.map((d) => d.id)}]`),\\\\n dappsUsed: (daos) =>\\\\n get(`api/dapps-used?${dateRange}&dao_list=[${daos.map((d) => d.id)}]`),\\\\n acquisitionCost: (daos) =>\\\\n get(\\\\n `api/acquisition-cost?${dateRange}&dao_list=[${daos.map((d) => d.id)}]`,\\\\n ),\\\\n socialEngagement: (daos) =>\\\\n get(\\\\n `api/social-engagement?${dateRange}&dao_list=[${daos.map((d) => d.id)}]`,\\\\n ),\\\\n};\\\\n\\\\nconst fetchData = () => {\\\\n setLoading(true);\\\\n\\\\n API.getTotal().then((resp) => {\\\\n if (!resp.body) return;\\\\n\\\\n const data = resp.body.data;\\\\n const newState = dataState;\\\\n newState.totalTx = data.transactions;\\\\n newState.totalAccounts = data.accounts;\\\\n newState.uniqueAccounts = data.active_users;\\\\n newState.totalBalance = data.totalBalance;\\\\n newState.distributed = data.distributed;\\\\n setDataState(newState);\\\\n setLoading(false);\\\\n });\\\\n\\\\n API.getDailyStats().then((resp) => {\\\\n if (!resp.body) return;\\\\n\\\\n const data = resp.body.data;\\\\n const newState = dataState;\\\\n newState.dailyStats = data;\\\\n setDataState(newState);\\\\n setLoading(false);\\\\n });\\\\n};\\\\n\\\\nuseEffect(() => {\\\\n formatDate();\\\\n}, [period]);\\\\n\\\\nuseEffect(() => {\\\\n if (dateRange) fetchData();\\\\n}, [selectedDAOs, daos, dateRange]);\\\\n\\\\nconst onSelectChange = (value) => {\\\\n const isDefaultOption = value === defaultDAOOption;\\\\n\\\\n const updateSelectedDAOs = () => {\\\\n if (isDefaultOption) {\\\\n const all = [...daos, defaultDAOOption];\\\\n if (selectedDAOs.length === all.length) {\\\\n return [];\\\\n }\\\\n return all;\\\\n } else if (selectedDAOs.includes(value)) {\\\\n return selectedDAOs.filter(\\\\n (dao) => dao !== value && dao !== defaultDAOOption,\\\\n );\\\\n } else {\\\\n return [...selectedDAOs, value];\\\\n }\\\\n };\\\\n\\\\n setSelectedDAOs(updateSelectedDAOs());\\\\n};\\\\n\\\\nconst capitalizeFirstLetter = (string) => {\\\\n return string.charAt(0).toUpperCase() + string.slice(1);\\\\n};\\\\n\\\\nreturn (\\\\n <Container>\\\\n <SelectContainer>\\\\n <Title>NDC Dashboard</Title>\\\\n <Filters>\\\\n <div className=\\\\\\\"d-flex flex-column gap-1\\\\\\\">\\\\n <div\\\\n role=\\\\\\\"button\\\\\\\"\\\\n className=\\\\\\\"wrapper\\\\\\\"\\\\n onClick={() => {\\\\n setShowDatePicker(!showDatePicker);\\\\n setMobile(false);\\\\n }}\\\\n >\\\\n <div className=\\\\\\\"value\\\\\\\">{`${formatDate().startDate} - ${\\\\n formatDate().endDate\\\\n }`}</div>\\\\n <i className=\\\\\\\"icon ph ph-calendar-blank\\\\\\\" />\\\\n </div>\\\\n <div\\\\n className=\\\\\\\"wrapper mobile\\\\\\\"\\\\n onClick={() => {\\\\n setShowDatePicker(!showDatePicker);\\\\n setMobile(true);\\\\n }}\\\\n >\\\\n <i className=\\\\\\\"icon ph ph-calendar-blank\\\\\\\" />\\\\n </div>\\\\n <Widget\\\\n src={`ndcdev.near/widget/dashboard.Components.DatePicker`}\\\\n props={{\\\\n period,\\\\n show: showDatePicker,\\\\n mobile,\\\\n handleChange: ({ startDate, endDate }) => {\\\\n setPeriod([startDate, endDate]);\\\\n setShowDatePicker(false);\\\\n },\\\\n }}\\\\n />\\\\n </div>\\\\n\\\\n <div className=\\\\\\\"w-100\\\\\\\">\\\\n <Widget\\\\n src={`ndcdev.near/widget/dashboard.Components.Switch`}\\\\n props={{\\\\n options: [\\\\n { title: \\\\\\\"Charts\\\\\\\", icon: \\\\\\\"ph ph-chart-bar\\\\\\\" },\\\\n { title: \\\\\\\"Table\\\\\\\", icon: \\\\\\\"ph ph-table\\\\\\\" },\\\\n ],\\\\n value: dashboardView,\\\\n onChange: () =>\\\\n setDashboardView(\\\\n dashboardView === \\\\\\\"Charts\\\\\\\" ? \\\\\\\"Table\\\\\\\" : \\\\\\\"Charts\\\\\\\",\\\\n ),\\\\n }}\\\\n />\\\\n </div>\\\\n </Filters>\\\\n </SelectContainer>\\\\n <Widget\\\\n src={`ndcdev.near/widget/dashboard.Components.Aggregators`}\\\\n props={{\\\\n totalTx: dataState.totalTx,\\\\n totalAccounts: dataState.totalAccounts,\\\\n uniqueAccounts: dataState.uniqueAccounts,\\\\n totalBalance: dataState.totalBalance,\\\\n totalDistributed: dataState.distributed,\\\\n }}\\\\n />\\\\n {dashboardView === \\\\\\\"Charts\\\\\\\" ? (\\\\n <ChartContainer>\\\\n <Widget\\\\n src={`ndcdev.near/widget/dashboard.Components.Chart`}\\\\n props={{\\\\n title: \\\\\\\"DAILY NUMBER OF TRANSACTIONS\\\\\\\",\\\\n data: dataState.dailyStats,\\\\n key: \\\\\\\"total_transactions\\\\\\\",\\\\n color: \\\\\\\"#A39ACD\\\\\\\",\\\\n loading,\\\\n }}\\\\n />\\\\n <Widget\\\\n src={`ndcdev.near/widget/dashboard.Components.Chart`}\\\\n props={{\\\\n title: \\\\\\\"UNIQUE ACTIVE USERS\\\\\\\",\\\\n data: dataState.dailyStats,\\\\n key: \\\\\\\"unique_wallets\\\\\\\",\\\\n color: \\\\\\\"#E89DBB\\\\\\\",\\\\n loading,\\\\n }}\\\\n />\\\\n </ChartContainer>\\\\n ) : (\\\\n <>\\\\n {loading ? (\\\\n <Loading />\\\\n ) : (\\\\n <div className=\\\\\\\"w-100 flex-column\\\\\\\">\\\\n <Widget\\\\n src={`ndcdev.near/widget/dashboard.Components.Table`}\\\\n props={{ daos, API, dateRange }}\\\\n />\\\\n </div>\\\\n )}\\\\n </>\\\\n )}\\\\n </Container>\\\\n);\\\\n" |
| 9 | "": "const Wrapper = styled.div`\\\\n width: 100%;\\\\n\\\\n .selected-container {\\\\n width: 100%;\\\\n display: flex;\\\\n justify-content: space-between;\\\\n align-items: center;\\\\n padding: 5px 16px;\\\\n gap: 10px;\\\\n font-size: 14px;\\\\n font-weight: 600;\\\\n\\\\n i {\\\\n color: #b0afb1;\\\\n }\\\\n\\\\n &.dao {\\\\n @media screen and (max-width: 768px) {\\\\n width: 100%;\\\\n }\\\\n }\\\\n }\\\\n`;\\\\n\\\\nconst DesktopFilters = styled.div`\\\\n display: flex;\\\\n width: 100%;\\\\n border-radius: 6px;\\\\n background: #f8f8f8;\\\\n\\\\n @media screen and (max-width: 1000px) {\\\\n gap: 40px;\\\\n }\\\\n\\\\n @media screen and (max-width: 768px) {\\\\n display: none;\\\\n }\\\\n`;\\\\n\\\\nconst MobileFilters = styled.div`\\\\n display: none;\\\\n width: 100%;\\\\n\\\\n @media screen and (max-width: 768px) {\\\\n display: flex;\\\\n flex-direction: column;\\\\n gap: 1rem;\\\\n }\\\\n\\\\n .filters {\\\\n display: flex;\\\\n flex-direction: column;\\\\n justify-content: center;\\\\n gap: 1rem;\\\\n }\\\\n`;\\\\n\\\\nconst { daos, API, dateRange } = props;\\\\nconst Loading = () => <Widget src=\\\\\\\"flashui.near/widget/Loading\\\\\\\" />;\\\\n\\\\nconst defaultDAOOption = \\\\\\\"All DAOs\\\\\\\";\\\\n\\\\nconst FILTER_IDS = {\\\\n dao: \\\\\\\"dao\\\\\\\",\\\\n userRetentions: \\\\\\\"userRetentions\\\\\\\",\\\\n dappsUsed: \\\\\\\"dappsUsed\\\\\\\",\\\\n acquisitionCost: \\\\\\\"acquisitionCost\\\\\\\",\\\\n};\\\\n\\\\nconst FILTER_OPENS = Object.keys(FILTER_IDS).map((item) => {\\\\n return { [item]: false };\\\\n});\\\\n\\\\nconst [dataSet, setDataSet] = useState([]);\\\\nconst [loading, setLoading] = useState(false);\\\\nconst [selectedDAOs, setSelectedDAOs] = useState(daos.map((d) => d.title));\\\\nconst [filteredData, setFilteredData] = useState([]);\\\\nconst [filtersIsOpen, setFiltersIsOpen] = useState(FILTER_OPENS);\\\\nconst [mobileFilters, setMobileFilters] = useState(flase);\\\\n\\\\nconst onFilterClick = (value) =>\\\\n setFiltersIsOpen({ ...FILTER_OPENS, [value]: !filtersIsOpen[value] });\\\\n\\\\nconst filterDAO = (value) => {\\\\n let newSelection;\\\\n\\\\n if (value === defaultDAOOption) {\\\\n const all = [defaultDAOOption, ...daos.map((d) => d.title)];\\\\n const isCurrentSelectionFull = selectedDAOs.length === all.length;\\\\n newSelection = isCurrentSelectionFull ? [] : all;\\\\n } else if (selectedDAOs.includes(value)) {\\\\n newSelection = selectedDAOs.filter(\\\\n (daoId) => daoId !== value && daoId !== defaultDAOOption,\\\\n );\\\\n } else {\\\\n newSelection = [...selectedDAOs, value];\\\\n }\\\\n\\\\n setSelectedDAOs(newSelection);\\\\n};\\\\n\\\\nconst fetchData = async (key) => {\\\\n setLoading(true);\\\\n const filtredDAOs = selectedDAOs.length\\\\n ? daos.filter((d) => selectedDAOs.includes(d.title))\\\\n : daos;\\\\n\\\\n let newDataSet = dataSet;\\\\n\\\\n API[key](filtredDAOs).then((resp) => {\\\\n if (!resp.body) return;\\\\n\\\\n const data = resp.body;\\\\n if (data)\\\\n Object.entries(data).map(([id, value]) => {\\\\n const targetData = newDataSet.find((d) => d.id === parseInt(id));\\\\n // targetData[key] = value;\\\\n targetData[key] = Math.random() * 10;\\\\n });\\\\n\\\\n // mocked data\\\\n newDataSet = [\\\\n {\\\\n id: 1,\\\\n title: \\\\\\\"HoM - Direct funding\\\\\\\",\\\\n userRetentions: 0.5,\\\\n dappsUsed: 3,\\\\n acquisitionCost: 1.5,\\\\n },\\\\n {\\\\n id: 2,\\\\n title: \\\\\\\"Build DAO\\\\\\\",\\\\n userRetentions: 0.75,\\\\n dappsUsed: 2,\\\\n acquisitionCost: 0,\\\\n },\\\\n {\\\\n id: 3,\\\\n title: \\\\\\\"Gaming DAO\\\\\\\",\\\\n userRetentions: 1,\\\\n dappsUsed: 10,\\\\n acquisitionCost: 24,\\\\n },\\\\n {\\\\n id: 4,\\\\n title: \\\\\\\"Marketing DAO\\\\\\\",\\\\n userRetentions: 1,\\\\n dappsUsed: 10,\\\\n acquisitionCost: 0,\\\\n },\\\\n {\\\\n id: 5,\\\\n title: \\\\\\\"Near Research Collective\\\\\\\",\\\\n userRetentions: 0.25,\\\\n dappsUsed: 1,\\\\n acquisitionCost: 0,\\\\n },\\\\n {\\\\n id: 6,\\\\n title: \\\\\\\"Degen DAO\\\\\\\",\\\\n userRetentions: 0.2,\\\\n dappsUsed: 4,\\\\n acquisitionCost: 34.5,\\\\n },\\\\n {\\\\n id: 7,\\\\n title: \\\\\\\"Onboard DAO\\\\\\\",\\\\n userRetentions: 0,\\\\n dappsUsed: 2,\\\\n acquisitionCost: 0,\\\\n },\\\\n {\\\\n id: 8,\\\\n title: \\\\\\\"Aurora Community DAO\\\\\\\",\\\\n userRetentions: 0.66,\\\\n dappsUsed: 3,\\\\n acquisitionCost: 0,\\\\n },\\\\n {\\\\n id: 9,\\\\n title: \\\\\\\"Near Globe DAO\\\\\\\",\\\\n userRetentions: 0,\\\\n dappsUsed: 0,\\\\n acquisitionCost: 0,\\\\n },\\\\n {\\\\n id: 10,\\\\n title: \\\\\\\"NFT DAO\\\\\\\",\\\\n userRetentions: 0.8,\\\\n dappsUsed: 3,\\\\n acquisitionCost: 0,\\\\n },\\\\n {\\\\n id: 11,\\\\n title: \\\\\\\"SHE IS NEAR\\\\\\\",\\\\n userRetentions: 0,\\\\n dappsUsed: 1,\\\\n acquisitionCost: 0.5,\\\\n },\\\\n {\\\\n id: 12,\\\\n title: \\\\\\\"Africa Community DAO\\\\\\\",\\\\n userRetentions: 0,\\\\n dappsUsed: 0,\\\\n acquisitionCost: 0,\\\\n },\\\\n {\\\\n id: 13,\\\\n title: \\\\\\\"Freelancer DAO\\\\\\\",\\\\n userRetentions: 0,\\\\n dappsUsed: 0,\\\\n acquisitionCost: 2.35,\\\\n },\\\\n {\\\\n id: 14,\\\\n title: \\\\\\\"Service DAO\\\\\\\",\\\\n userRetentions: 0,\\\\n dappsUsed: 0,\\\\n acquisitionCost: 0.46,\\\\n },\\\\n {\\\\n id: 15,\\\\n title: \\\\\\\"SMM\\\\\\\",\\\\n userRetentions: 0,\\\\n dappsUsed: 3,\\\\n acquisitionCost: 0.1,\\\\n },\\\\n {\\\\n id: 16,\\\\n title: \\\\\\\"NDC Ops\\\\\\\",\\\\n userRetentions: 1,\\\\n dappsUsed: 4,\\\\n acquisitionCost: 2,\\\\n },\\\\n {\\\\n id: 17,\\\\n title: \\\\\\\"HoM - Grassroot DAOs funding\\\\\\\",\\\\n userRetentions: 1,\\\\n dappsUsed: 12,\\\\n acquisitionCost: 0.75,\\\\n },\\\\n ];\\\\n\\\\n setDataSet(newDataSet);\\\\n setFilteredData(newDataSet);\\\\n setLoading(false);\\\\n });\\\\n};\\\\n\\\\nuseEffect(() => {\\\\n const filtredDAOs = selectedDAOs.length\\\\n ? daos.filter((d) => selectedDAOs.includes(d.title))\\\\n : daos;\\\\n\\\\n if (dataSet.length === 0)\\\\n setDataSet(\\\\n filtredDAOs.map((dao) => {\\\\n return {\\\\n id: dao.id,\\\\n title: dao.title,\\\\n [FILTER_IDS.userRetentions]: 0,\\\\n [FILTER_IDS.dappsUsed]: 0,\\\\n [FILTER_IDS.acquisitionCost]: 0,\\\\n };\\\\n }),\\\\n );\\\\n\\\\n setFilteredData(\\\\n dataSet.filter((d) => filtredDAOs.map((dd) => dd.title).includes(d.title)),\\\\n );\\\\n}, [selectedDAOs]);\\\\n\\\\nuseEffect(() => {\\\\n console.log(dataSet, dateRange);\\\\n if (dataSet.length > 0 && dateRange) {\\\\n fetchData(FILTER_IDS.userRetentions);\\\\n fetchData(FILTER_IDS.dappsUsed);\\\\n fetchData(FILTER_IDS.acquisitionCost);\\\\n }\\\\n}, [dataSet, dateRange]);\\\\n\\\\nconst sortData = (field) =>\\\\n setDataSet(filteredData.sort((a, b) => b[field] - a[field]));\\\\n\\\\nconst SortingRow = ({ title, field }) => (\\\\n <div className=\\\\\\\"selected-container\\\\\\\">\\\\n <div className=\\\\\\\"d-flex align-items-end gap-2\\\\\\\">\\\\n <i className=\\\\\\\"ph ph-info fs-5\\\\\\\" />\\\\n <div>{title}</div>\\\\n </div>\\\\n <i\\\\n role=\\\\\\\"button\\\\\\\"\\\\n className=\\\\\\\"ph ph-caret-up-down fs-5\\\\\\\"\\\\n onClick={() => sortData(field)}\\\\n />\\\\n </div>\\\\n);\\\\n\\\\nreturn (\\\\n <Wrapper>\\\\n <MobileFilters>\\\\n <div className=\\\\\\\"w-100 gap-3 d-flex justify-content-between align-items-center\\\\\\\">\\\\n <Widget\\\\n src={`ndcdev.near/widget/dashboard.Components.Select`}\\\\n props={{\\\\n id: FILTER_IDS.dao,\\\\n text: \\\\\\\"DAO\\\\\\\",\\\\n hintText: \\\\\\\"NDC grassroots DAOs\\\\\\\",\\\\n options: daos.map((d) => d.title),\\\\n values: selectedDAOs,\\\\n defaultValue: defaultDAOOption,\\\\n multiple: true,\\\\n filterIsOpen: filtersIsOpen[FILTER_IDS.dao],\\\\n onFilterClick,\\\\n onChange: (value) => filterDAO(value),\\\\n onClear: () => {\\\\n setSelectedDAOs([]);\\\\n },\\\\n isTooltipVisible: true,\\\\n noBorder: true,\\\\n containerClass: \\\\\\\"selected-container dao\\\\\\\",\\\\n }}\\\\n />\\\\n <div\\\\n role=\\\\\\\"button\\\\\\\"\\\\n className=\\\\\\\"btn btn-secondary outlined btn-icon\\\\\\\"\\\\n onClick={() => setMobileFilters(!mobileFilters)}\\\\n >\\\\n <i className=\\\\\\\"ph ph-funnel fs-5\\\\\\\" />\\\\n </div>\\\\n </div>\\\\n {mobileFilters && (\\\\n <div className=\\\\\\\"filters\\\\\\\">\\\\n <SortingRow\\\\n title=\\\\\\\"User Retention\\\\\\\"\\\\n field={FILTER_IDS.userRetentions}\\\\n />\\\\n <SortingRow title=\\\\\\\"DApp\\\\\\'s Used\\\\\\\" field={FILTER_IDS.dappsUsed} />\\\\n <SortingRow\\\\n title=\\\\\\\"Acquisition Cost\\\\\\\"\\\\n field={FILTER_IDS.acquisitionCost}\\\\n />\\\\n </div>\\\\n )}\\\\n </MobileFilters>\\\\n <DesktopFilters>\\\\n <div className=\\\\\\\"w-100 gap-5 d-flex justify-content-between align-items-center\\\\\\\">\\\\n <Widget\\\\n src={`ndcdev.near/widget/dashboard.Components.Select`}\\\\n props={{\\\\n id: FILTER_IDS.dao,\\\\n text: \\\\\\\"DAO\\\\\\\",\\\\n hintText: \\\\\\\"NDC grassroots DAOs\\\\\\\",\\\\n options: daos.map((d) => d.title),\\\\n values: selectedDAOs,\\\\n defaultValue: defaultDAOOption,\\\\n multiple: true,\\\\n filterIsOpen: filtersIsOpen[FILTER_IDS.dao],\\\\n onFilterClick,\\\\n onChange: (value) => filterDAO(value),\\\\n onClear: () => {\\\\n setSelectedDAOs([]);\\\\n },\\\\n isTooltipVisible: true,\\\\n noBorder: true,\\\\n containerClass: \\\\\\\"selected-container dao\\\\\\\",\\\\n }}\\\\n />\\\\n <SortingRow title=\\\\\\\"User Retention\\\\\\\" field={FILTER_IDS.userRetentions} />\\\\n <SortingRow title=\\\\\\\"DApp\\\\\\'s Used\\\\\\\" field={FILTER_IDS.dappsUsed} />\\\\n <SortingRow\\\\n title=\\\\\\\"Acquisition Cost\\\\\\\"\\\\n field={FILTER_IDS.acquisitionCost}\\\\n />\\\\n </div>\\\\n </DesktopFilters>\\\\n <Widget\\\\n src={`ndcdev.near/widget/dashboard.Components.Table.Cells`}\\\\n props={{ dataSet: filteredData, loading }}\\\\n />\\\\n </Wrapper>\\\\n);\\\\n" |
| 12 | "": "const { dataSet, loading } = props;\\\\n\\\\nconst Loading = <Widget src=\\\\\\\"flashui.near/widget/Loading\\\\\\\" />;\\\\n\\\\nconst DesktopRow = styled.div`\\\\n display: flex;\\\\n padding: 16px;\\\\n align-items: center;\\\\n gap: 72px;\\\\n align-self: stretch;\\\\n border-bottom: 1px solid #e3e3e0;\\\\n\\\\n @media screen and (max-width: 768px) {\\\\n display: none;\\\\n }\\\\n\\\\n .desktop-value {\\\\n min-width: 100px;\\\\n width: 100%;\\\\n display: flex;\\\\n align-items: center;\\\\n justify-content: center;\\\\n text-align: center;\\\\n font-size: 12px;\\\\n font-style: normal;\\\\n font-weight: 600;\\\\n position: relative;\\\\n border-radius: 100px;\\\\n\\\\n span {\\\\n z-index: 100;\\\\n }\\\\n }\\\\n`;\\\\n\\\\nconst MobileRow = styled.div`\\\\n display: none;\\\\n width: 100%;\\\\n padding: 24px;\\\\n flex-direction: column;\\\\n align-items: flex-start;\\\\n gap: 20px;\\\\n border-radius: 12px;\\\\n border: 1px solid #e3e3e0;\\\\n background: var(--Primary-Base-White, #fff);\\\\n box-shadow:\\\\n 0px 97px 27px 0px rgba(0, 0, 0, 0),\\\\n 0px 62px 25px 0px rgba(0, 0, 0, 0),\\\\n 0px 35px 21px 0px rgba(0, 0, 0, 0.02),\\\\n 0px 16px 16px 0px rgba(0, 0, 0, 0.03),\\\\n 0px 4px 9px 0px rgba(0, 0, 0, 0.03);\\\\n\\\\n @media screen and (max-width: 768px) {\\\\n display: flex;\\\\n }\\\\n\\\\n .mobile-cell {\\\\n display: flex;\\\\n flex-direction: column;\\\\n gap: 10px;\\\\n padding-bottom: 12px;\\\\n align-self: stretch;\\\\n border-bottom: 1px solid #e3e3e0;\\\\n\\\\n .mobile-value {\\\\n width: 100%;\\\\n display: flex;\\\\n justify-content: space-between;\\\\n align-items: center;\\\\n\\\\n .title {\\\\n font-size: 14px;\\\\n font-style: normal;\\\\n font-weight: 500;\\\\n color: #5c656a;\\\\n }\\\\n }\\\\n }\\\\n`;\\\\n\\\\nconst Colored = styled.div`\\\\n width: 100%;\\\\n display: flex;\\\\n align-items: center;\\\\n justify-content: center;\\\\n position: relative;\\\\n border-radius: 100px;\\\\n background: #f5f5f5;\\\\n height: ${(props) => props.height}px;\\\\n\\\\n .value {\\\\n position: absolute;\\\\n height: ${(props) => props.height}px;\\\\n left: 0;\\\\n width: ${(props) => props.width ?? 0}%;\\\\n background: ${(props) => props.color ?? \\\\\\\"inherit\\\\\\\"};\\\\n border-radius: ${(props) =>\\\\n props.width === 100 ? \\\\\\\"100px\\\\\\\" : \\\\\\\"100px 0 0 100px\\\\\\\"};\\\\n }\\\\n`;\\\\n\\\\nconst Container = styled.div`\\\\n display: flex;\\\\n flex-direction: column;\\\\n gap: 1rem;\\\\n align-items: flex-start;\\\\n padding-top: 1rem;\\\\n`;\\\\n\\\\nconst DaoName = styled.div`\\\\n width: 100%;\\\\n text-overflow: ellipsis;\\\\n overflow: hidden;\\\\n text-wrap: nowrap;\\\\n font-size: 16px;\\\\n font-weight: 600;\\\\n justify-content: flex-start;\\\\n background: transparent;\\\\n`;\\\\n\\\\nconst TRESHOLD = 75;\\\\n\\\\nconst dappUsedPercentage = (value) =>\\\\n parseFloat(value / Math.max(...dataSet.map((d) => d.dappsUsed))) * 100;\\\\n\\\\nconst getPercentage = (min, max) => parseFloat(min / max) * 100;\\\\n\\\\nconst formatValue = (value) => {\\\\n const val = value ? parseFloat(value) : null;\\\\n\\\\n if (!val) return \\\\\\\"n/a\\\\\\\";\\\\n\\\\n return val >= 1000000000\\\\n ? `${parseFloat(val / 1000000000).toFixed(2)}B`\\\\n : val >= 1000000\\\\n ? `${parseFloat(val / 1000000).toFixed(2)}M`\\\\n : val >= 1000\\\\n ? `${parseFloat(val / 1000).toFixed(2)}K`\\\\n : Number.isInteger(val)\\\\n ? val\\\\n : val.toFixed(2);\\\\n};\\\\n\\\\nconst TooltipContent = ({ key, value }) => (\\\\n <div className=\\\\\\\"justify-content-between w-100 d-flex gap-2\\\\\\\">\\\\n <div>{key}:</div> <div>{formatValue(value)}</div>\\\\n </div>\\\\n);\\\\n\\\\nconst DesktopCell = ({ width, color, value }) => (\\\\n <div className=\\\\\\\"desktop-value\\\\\\\">\\\\n <Colored width={width} color={color} height={22}>\\\\n <div className=\\\\\\\"value\\\\\\\"></div>\\\\n <span>{formatValue(value)}</span>\\\\n </Colored>\\\\n </div>\\\\n);\\\\n\\\\nconst MobileCell = ({ title, value, width, color }) => (\\\\n <div className=\\\\\\\"mobile-cell\\\\\\\">\\\\n <div className=\\\\\\\"mobile-value\\\\\\\">\\\\n <div className=\\\\\\\"d-flex gap-1 title\\\\\\\">\\\\n <i className=\\\\\\\"ph ph-info\\\\\\\" />\\\\n <span>{title}</span>\\\\n </div>\\\\n {formatValue(value)}\\\\n </div>\\\\n\\\\n <Colored width={width} color={color} height={10}>\\\\n <div className=\\\\\\\"value\\\\\\\"></div>\\\\n </Colored>\\\\n </div>\\\\n);\\\\n\\\\nreturn (\\\\n <Container>\\\\n {dataSet.map(\\\\n ({ title, userRetentions, dappsUsed, acquisitionCost }, index) => (\\\\n <>\\\\n <DesktopRow>\\\\n <DaoName>{title}</DaoName>\\\\n <DesktopCell\\\\n width={getPercentage(userRetentions, 1)}\\\\n color={\\\\n getPercentage(userRetentions, 1) >= TRESHOLD\\\\n ? \\\\\\\"#51D38E\\\\\\\"\\\\n : \\\\\\\"#FC6F60\\\\\\\"\\\\n }\\\\n value={userRetentions}\\\\n />\\\\n <DesktopCell\\\\n width={dappUsedPercentage(dappsUsed)}\\\\n color={\\\\n dappUsedPercentage(dappsUsed) >= TRESHOLD\\\\n ? \\\\\\\"#51D38E\\\\\\\"\\\\n : \\\\\\\"#FC6F60\\\\\\\"\\\\n }\\\\n value={dappsUsed}\\\\n />\\\\n <DesktopCell\\\\n width={\\\\n acquisitionCost < 1 ? getPercentage(1 - acquisitionCost, 1) : 5\\\\n }\\\\n color={\\\\n acquisitionCost && (acquisitionCost < 1 ? \\\\\\\"#51D38E\\\\\\\" : \\\\\\\"#FC6F60\\\\\\\")\\\\n }\\\\n value={acquisitionCost}\\\\n />\\\\n </DesktopRow>\\\\n\\\\n <MobileRow>\\\\n <DaoName>{title}</DaoName>\\\\n <MobileCell\\\\n title=\\\\\\\"User Retention\\\\\\\"\\\\n width={getPercentage(userRetentions, 10, 2)}\\\\n color={userRetentions >= 1 ? \\\\\\\"#51D38E\\\\\\\" : \\\\\\\"#FC6F60\\\\\\\"}\\\\n value={userRetentions}\\\\n />\\\\n <MobileCell\\\\n title=\\\\\\\"DApp\\\\\\'s Used\\\\\\\"\\\\n width={getPercentage(dappsUsed, 10, 2)}\\\\n color={\\\\\\\"#51D38E\\\\\\\"}\\\\n value={dappsUsed}\\\\n />\\\\n <MobileCell\\\\n title=\\\\\\\"Acquisition Cost\\\\\\\"\\\\n width={getPercentage(acquisitionCost, 10, 2)}\\\\n color={acquisitionCost < 1 ? \\\\\\\"#51D38E\\\\\\\" : \\\\\\\"#FC6F60\\\\\\\"}\\\\n value={acquisitionCost}\\\\n />\\\\n </MobileRow>\\\\n </>\\\\n ),\\\\n )}\\\\n </Container>\\\\n);\\\\n" |