parent
25f44b84df
commit
f2ed2c6642
|
@ -7,8 +7,9 @@ import CopyButton from 'components/common/CopyButton';
|
|||
|
||||
export default function TrackingCodeForm({ values, onClose }) {
|
||||
const ref = useRef();
|
||||
const ref1 = useRef();
|
||||
const { basePath } = useRouter();
|
||||
const { name, shareId } = values;
|
||||
const { name, shareId, websiteUuid } = values;
|
||||
|
||||
return (
|
||||
<FormLayout>
|
||||
|
@ -33,6 +34,30 @@ export default function TrackingCodeForm({ values, onClose }) {
|
|||
</FormRow>
|
||||
<FormButtons>
|
||||
<CopyButton type="submit" variant="action" element={ref} />
|
||||
</FormButtons>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="message.embedded-url"
|
||||
defaultMessage="This is the public embedded code for {target}."
|
||||
values={{ target: <b>{values.name}</b> }}
|
||||
/>
|
||||
</p>
|
||||
<FormRow>
|
||||
<textarea
|
||||
ref={ref1}
|
||||
rows={3}
|
||||
cols={60}
|
||||
spellCheck={false}
|
||||
defaultValue={`<canvas id="unamiChart" style="height: 300px;" data-url="${document.location.origin}${basePath}" data-website="${websiteUuid}" data-share-id="${shareId}" data-reload="5" data-start-at="auto" data-end-at="auto" data-unit="hour" data-tz="Asia/Dhaka"></canvas>
|
||||
<script src="${document.location.origin}/embedded.js"></script>
|
||||
`}
|
||||
readOnly
|
||||
/>
|
||||
</FormRow>
|
||||
<FormButtons>
|
||||
<CopyButton type="submit" variant="action" element={ref1} />
|
||||
</FormButtons>
|
||||
<FormButtons>
|
||||
<Button onClick={onClose}>
|
||||
<FormattedMessage id="label.cancel" defaultMessage="Cancel" />
|
||||
</Button>
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/* eslint-disable */
|
||||
if (typeof jQuery === 'undefined') {
|
||||
const script = document.createElement('script');
|
||||
script.src = '//code.jquery.com/jquery.js';
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
if (typeof Chart === 'undefined') {
|
||||
const script = document.createElement('script');
|
||||
script.src = '//cdn.jsdelivr.net/npm/chart.js';
|
||||
script.onload = function () {
|
||||
window.unamiChart = false;
|
||||
loadUnamiStat();
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
function loadUnamiStat() {
|
||||
var startAt = $('#unamiChart').data('start-at');
|
||||
var endAt = $('#unamiChart').data('end-at');
|
||||
var unit = $('#unamiChart').data('unit');
|
||||
var tz = $('#unamiChart').data('tz');
|
||||
var shareId = $('#unamiChart').data('share-id');
|
||||
var reload = Number($('#unamiChart').data('reload'));
|
||||
if ($('#unamiChart').length) {
|
||||
loadUnamiDataAjax(startAt, endAt, unit, tz, shareId);
|
||||
if (reload > 0) {
|
||||
setInterval(function () {
|
||||
loadUnamiDataAjax(startAt, endAt, unit, tz, shareId);
|
||||
}, 1000 * reload);
|
||||
}
|
||||
} else {
|
||||
alert('canvas#unamiChart does not exist!');
|
||||
}
|
||||
}
|
||||
|
||||
function loadUnamiDataAjax(startAt, endAt, unit, tz, shareId) {
|
||||
if (startAt == 'auto') {
|
||||
startAt = new Date() * 1 - 24 * 3600 * 1000;
|
||||
}
|
||||
if (endAt == 'auto') {
|
||||
endAt = new Date() * 1;
|
||||
}
|
||||
var website = $('#unamiChart').data('website');
|
||||
var apiUrl = $('#unamiChart').data('url');
|
||||
var chartOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
legend: { position: 'top' },
|
||||
scales: { x: { stacked: true }, y: { stacked: true } },
|
||||
};
|
||||
var url = `${apiUrl}/api/websites/${website}/pageviews?start_at=${startAt}&end_at=${endAt}&unit=${unit}&tz=${tz}&shareId=${shareId}`;
|
||||
$.ajax({
|
||||
method: 'GET',
|
||||
url: url,
|
||||
success: function (data) {
|
||||
var labels = data.pageviews.map(p => {
|
||||
var date = new Date(p.t);
|
||||
var hours = date.getHours();
|
||||
return `${hours === 0 ? 12 : hours > 12 ? hours - 12 : hours}${hours < 12 ? 'AM' : 'PM'}`;
|
||||
});
|
||||
|
||||
var pageviewsData = data.pageviews.map(p => p.y);
|
||||
var sessionsData = data.sessions.map(s => s.y);
|
||||
|
||||
var chartData = {
|
||||
labels: labels,
|
||||
datasets: [
|
||||
{
|
||||
label: 'Unique visitors',
|
||||
data: sessionsData,
|
||||
backgroundColor: 'rgba(38, 128, 235, 0.6)',
|
||||
borderColor: 'rgba(38, 128, 235, 0.7)',
|
||||
},
|
||||
{
|
||||
label: 'Page views',
|
||||
data: pageviewsData,
|
||||
backgroundColor: 'rgba(38, 128, 235, 0.4)',
|
||||
borderColor: 'rgba(38, 128, 235, 0.5)',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if (!window.unamiChart) {
|
||||
var ctx = document.getElementById('unamiChart').getContext('2d');
|
||||
window.unamiChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: chartData,
|
||||
options: chartOptions,
|
||||
});
|
||||
} else {
|
||||
window.unamiChart.data = chartData;
|
||||
window.unamiChart.update('none');
|
||||
}
|
||||
},
|
||||
error: function (error) {
|
||||
console.log(error);
|
||||
},
|
||||
});
|
||||
}
|
|
@ -94,6 +94,7 @@
|
|||
"message.track-stats": "To track stats for {target}, place the following code in the {head} section of your website.",
|
||||
"message.type-delete": "Type {delete} in the box below to confirm.",
|
||||
"message.type-reset": "Type {reset} in the box below to confirm.",
|
||||
"message.embedded-url": "This is the public embedded code for {target}.",
|
||||
"metrics.actions": "Actions",
|
||||
"metrics.average-visit-time": "Average visit time",
|
||||
"metrics.bounce-rate": "Bounce rate",
|
||||
|
|
|
@ -2,6 +2,7 @@ import { createMiddleware, unauthorized, badRequest, serverError } from 'next-ba
|
|||
import cors from 'cors';
|
||||
import { getSession } from './session';
|
||||
import { getAuthToken, getShareToken } from './auth';
|
||||
import { getWebsite } from 'queries';
|
||||
|
||||
export const useCors = createMiddleware(
|
||||
cors({
|
||||
|
@ -32,7 +33,14 @@ export const useSession = createMiddleware(async (req, res, next) => {
|
|||
|
||||
export const useAuth = createMiddleware(async (req, res, next) => {
|
||||
const token = await getAuthToken(req);
|
||||
const shareToken = await getShareToken(req);
|
||||
let shareToken = await getShareToken(req);
|
||||
// create share token if shareId and website exist
|
||||
if (req?.query?.shareId) {
|
||||
const website = await getWebsite({ shareId: req?.query?.shareId });
|
||||
if (website) {
|
||||
shareToken = { id: website?.websiteUuid };
|
||||
}
|
||||
}
|
||||
|
||||
if (!token && !shareToken) {
|
||||
return unauthorized(res);
|
||||
|
|
|
@ -11,14 +11,15 @@
|
|||
},
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "npm-run-all build-db check-db build-tracker build-geo build-app",
|
||||
"build": "npm-run-all build-db check-db build-tracker build-embedded build-geo build-app",
|
||||
"start": "next start",
|
||||
"build-docker": "npm-run-all build-db build-tracker build-geo build-app",
|
||||
"build-docker": "npm-run-all build-db build-tracker build-embedded build-geo build-app",
|
||||
"start-docker": "npm-run-all check-db update-tracker start-server",
|
||||
"start-env": "node scripts/start-env.js",
|
||||
"start-server": "node server.js",
|
||||
"build-app": "next build",
|
||||
"build-tracker": "rollup -c rollup.tracker.config.js",
|
||||
"build-embedded": "rollup -c rollup.embedded.config.js",
|
||||
"build-db": "npm-run-all copy-db-files build-db-client",
|
||||
"build-lang": "npm-run-all format-lang compile-lang download-country-names download-language-names",
|
||||
"build-geo": "node scripts/build-geo.js",
|
||||
|
|
|
@ -4,6 +4,7 @@ import { ok, badRequest, methodNotAllowed, unauthorized } from 'next-basics';
|
|||
import { allowQuery } from 'lib/auth';
|
||||
import { useAuth, useCors } from 'lib/middleware';
|
||||
import { TYPE_WEBSITE } from 'lib/constants';
|
||||
import { getDateArray } from 'lib/date';
|
||||
|
||||
const unitTypes = ['year', 'month', 'hour', 'day'];
|
||||
|
||||
|
@ -12,7 +13,7 @@ export default async (req, res) => {
|
|||
await useAuth(req, res);
|
||||
|
||||
if (req.method === 'GET') {
|
||||
if (!(await allowQuery(req, TYPE_WEBSITE))) {
|
||||
if (!(await allowQuery(req, TYPE_WEBSITE, true))) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
|
@ -69,7 +70,10 @@ export default async (req, res) => {
|
|||
}),
|
||||
]);
|
||||
|
||||
return ok(res, { pageviews, sessions });
|
||||
let _pageviews = getDateArray(pageviews, startDate, endDate, unit);
|
||||
let _sessions = getDateArray(sessions, startDate, endDate, unit);
|
||||
|
||||
return ok(res, { pageviews: _pageviews, sessions: _sessions });
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import 'dotenv/config';
|
||||
import buble from '@rollup/plugin-buble';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
|
||||
export default {
|
||||
input: 'embedded/index.js',
|
||||
output: {
|
||||
file: 'public/embedded.js',
|
||||
format: 'iife',
|
||||
},
|
||||
plugins: [buble({ objectAssign: true }), terser({ compress: { evaluate: false } })],
|
||||
};
|
Loading…
Reference in New Issue