Modular JavaScript libraries for managing tasks in a traffic exchange system. Framework-agnostic core written in TypeScript, with a React wrapper for UI integration.
| Package | npm | Description |
|---|---|---|
make-traffic-integration-core |
Core library — framework-agnostic | |
make-traffic-integration-react-wrapper |
React hook + provider |
| Example | Stack | Complexity | README |
|---|---|---|---|
examples/native-js |
Vanilla JS, no build | Minimal | README |
examples/native-ts |
Vanilla TS, tsc | Minimal | README |
examples/react-app |
React 18, Tailwind | Simple → Full | README |
# Core only (vanilla JS/TS)
npm install make-traffic-integration-core
# React projects
npm install make-traffic-integration-core make-traffic-integration-react-wrapperimport { NewTaskManager, Events } from "make-traffic-integration-core";
const manager = await NewTaskManager({
apiUrl: "https://integration.maketraffic.io",
appKey: "<!--YourAppKey-->",
});
const { data: tasks } = await manager.getTasks("user-123");
manager.subscribe(Events.TaskClaimSucceed, (task) => {
console.log("Claimed:", task.name, task.rewards);
});import { useTaskManager } from "make-traffic-integration-react-wrapper";
const { tasks, isLoading, error, goProcess, claimProcess } = useTaskManager({
taskManagerApp: app,
userID: "user-123",
authProvider: "telegram",
});Initialises the library, loads plugin scripts, and stores the instance on window.globalTaskManager.
Prefer this over new TaskManagerApp(config) + init() in most cases.
Fetches tasks for the user. Supports filtering by isActive, categories, pluginIds, entityType, page, pageSize, authProvider.
Triggers the task's go/start action (e.g. opens a redirect). Emits Events.ClickOnTaskGo.
Claims the reward. On success emits Events.TaskClaimSucceed. On conflict (409) emits Events.TaskClaimFailed and rejects with an HttpError containing the server message.
Event pub/sub. Always unsubscribe in cleanup (React useEffect return, component unmount).
| Event | Payload | When |
|---|---|---|
Events.TaskClaimSucceed |
Task |
Reward successfully claimed |
Events.TaskClaimFailed |
Task |
Claim rejected (e.g. task not completed) |
Events.ClickOnTaskGo |
Task |
Go button triggered |
Events.ClickOnTaskClaim |
Task |
Claim button triggered |
Events.ClaimModalOpen |
ClaimModalOpenPayload |
Plugin needs a UI container |
Events.ClaimModalClosed |
ClaimModalClosedPayload |
Modal dismissed |
Initialise once outside the component tree and store on window so it is accessible before React mounts and across components without prop drilling.
// examples/react-app/src/examples/full/config.ts
NewTaskManager(APP_CONFIG).then((manager) => {
window.globalTaskManager = manager;
});Call refresh() explicitly after both goProcess and claimProcess succeed. Do not refresh on failure — the server state has not changed.
// After go
onGo={() => goProcess(task).then(refresh)}
// After claim
await claimProcess(task);
refresh();Subscribe inside useEffect and always return the unsubscribe function. Use events for cross-cutting concerns (notifications, analytics) rather than coupling them to action handlers.
React.useEffect(() => {
const manager = window.globalTaskManager;
if (!manager) return;
manager.subscribe(Events.TaskClaimSucceed, showSuccess);
return () => manager.unsubscribe(Events.TaskClaimSucceed, showSuccess);
}, []);claimProcess rejects with HttpError on failure. Read err.message — the library parses the server's JSON error body so the message is human-readable (e.g. "task has not been completed").
const handleClaim = async (task: Task) => {
try {
await claimProcess(task);
refresh();
} catch (err: any) {
showError(err?.message || "Failed to claim task");
}
};Some plugins (e.g. quiz) need a UI surface to render into. Place TaskClaimModalHost once near the root of your app. It listens for ClaimModalOpen, opens a modal shell, and hands a DOM container to the plugin via provideHost. The plugin owns what renders inside; the host owns open/close state and emits ClaimModalClosed.
<TaskClaimModalHost taskManagerApp={window.globalTaskManager} />→ full/App.tsx · → TaskClaimModalHost.tsx
task.customMetadata is untyped (object | null). Use the plugin registry helpers to extract typed metadata, or cast locally for simple fields.
import { pluginRegistry, getRewardValue, getTaskIconUrl } from "make-traffic-integration-react-wrapper";
// Typed metadata for redirect plugin
const meta = pluginRegistry.redirect.getMetadata(task); // { url, secondsToClaim }
// Reward amount by type
const coins = getRewardValue(task.rewards, "coin");
// Icon URL with fallback to www.svg
const iconUrl = getTaskIconUrl(task, "/icons");Pass authProvider to every call that reaches the API — getTasks, goProcess, claimProcess. Centralise it in config so it never diverges.
// config.ts
export const AUTH_PROVIDER = "telegram";
// useTaskManager / goProcess / claimProcess all forward it:
const { ... } = useTaskManager({ ..., authProvider: AUTH_PROVIDER });Use filters in getTasks / useTaskManager to reduce payload size. Filter server-side by plugin type, category or active state rather than filtering the full list client-side.
useTaskManager({
filters: {
isActive: true, // active tasks only (default)
categories: ["default"], // specific categories
pluginIds: [2, 4], // specific plugins
},
});→ full/App.tsx · → HttpClient.ts
MIT