parent
25f44b84df
commit
f2ed2c6642
|
@ -7,8 +7,9 @@ import CopyButton from 'components/common/CopyButton';
|
||||||
|
|
||||||
export default function TrackingCodeForm({ values, onClose }) {
|
export default function TrackingCodeForm({ values, onClose }) {
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
|
const ref1 = useRef();
|
||||||
const { basePath } = useRouter();
|
const { basePath } = useRouter();
|
||||||
const { name, shareId } = values;
|
const { name, shareId, websiteUuid } = values;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormLayout>
|
<FormLayout>
|
||||||
|
@ -33,6 +34,30 @@ export default function TrackingCodeForm({ values, onClose }) {
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<FormButtons>
|
<FormButtons>
|
||||||
<CopyButton type="submit" variant="action" element={ref} />
|
<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}>
|
<Button onClick={onClose}>
|
||||||
<FormattedMessage id="label.cancel" defaultMessage="Cancel" />
|
<FormattedMessage id="label.cancel" defaultMessage="Cancel" />
|
||||||
</Button>
|
</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.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-delete": "Type {delete} in the box below to confirm.",
|
||||||
"message.type-reset": "Type {reset} 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.actions": "Actions",
|
||||||
"metrics.average-visit-time": "Average visit time",
|
"metrics.average-visit-time": "Average visit time",
|
||||||
"metrics.bounce-rate": "Bounce rate",
|
"metrics.bounce-rate": "Bounce rate",
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { createMiddleware, unauthorized, badRequest, serverError } from 'next-ba
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
import { getSession } from './session';
|
import { getSession } from './session';
|
||||||
import { getAuthToken, getShareToken } from './auth';
|
import { getAuthToken, getShareToken } from './auth';
|
||||||
|
import { getWebsite } from 'queries';
|
||||||
|
|
||||||
export const useCors = createMiddleware(
|
export const useCors = createMiddleware(
|
||||||
cors({
|
cors({
|
||||||
|
@ -32,7 +33,14 @@ export const useSession = createMiddleware(async (req, res, next) => {
|
||||||
|
|
||||||
export const useAuth = createMiddleware(async (req, res, next) => {
|
export const useAuth = createMiddleware(async (req, res, next) => {
|
||||||
const token = await getAuthToken(req);
|
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) {
|
if (!token && !shareToken) {
|
||||||
return unauthorized(res);
|
return unauthorized(res);
|
||||||
|
|
|
@ -11,14 +11,15 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"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",
|
"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-docker": "npm-run-all check-db update-tracker start-server",
|
||||||
"start-env": "node scripts/start-env.js",
|
"start-env": "node scripts/start-env.js",
|
||||||
"start-server": "node server.js",
|
"start-server": "node server.js",
|
||||||
"build-app": "next build",
|
"build-app": "next build",
|
||||||
"build-tracker": "rollup -c rollup.tracker.config.js",
|
"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-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-lang": "npm-run-all format-lang compile-lang download-country-names download-language-names",
|
||||||
"build-geo": "node scripts/build-geo.js",
|
"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 { allowQuery } from 'lib/auth';
|
||||||
import { useAuth, useCors } from 'lib/middleware';
|
import { useAuth, useCors } from 'lib/middleware';
|
||||||
import { TYPE_WEBSITE } from 'lib/constants';
|
import { TYPE_WEBSITE } from 'lib/constants';
|
||||||
|
import { getDateArray } from 'lib/date';
|
||||||
|
|
||||||
const unitTypes = ['year', 'month', 'hour', 'day'];
|
const unitTypes = ['year', 'month', 'hour', 'day'];
|
||||||
|
|
||||||
|
@ -12,7 +13,7 @@ export default async (req, res) => {
|
||||||
await useAuth(req, res);
|
await useAuth(req, res);
|
||||||
|
|
||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
if (!(await allowQuery(req, TYPE_WEBSITE))) {
|
if (!(await allowQuery(req, TYPE_WEBSITE, true))) {
|
||||||
return unauthorized(res);
|
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);
|
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