Skip to content

Commit

Permalink
feat: add proper campaign selection to module settings
Browse files Browse the repository at this point in the history
  • Loading branch information
eXaminator committed Nov 4, 2020
1 parent 8e5b82b commit 8732493
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 72 deletions.
4 changes: 0 additions & 4 deletions src/types.d.ts → src/globalTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,3 @@ declare module '*.png' {
const content: string;
export default content;
}

interface App {

}
11 changes: 5 additions & 6 deletions src/hooks/init.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { info } from '../logger';
import { logInfo } from '../logger';
import preloadTemplates from '../module/preloadTemplates';
import { clearSettings, registerSettings } from '../module/settings';
import { clearSettings, registerSettings } from '../module/configureSettings';

export default async function init(...args: unknown[]): Promise<void> {
info('Initializing', args);
registerSettings();
game.settings.sheet.render(); // update sheet if it already visible
export default async function init(): Promise<void> {
logInfo('Initializing');
await registerSettings();

await preloadTemplates();
}
Expand Down
10 changes: 6 additions & 4 deletions src/hooks/renderJournalDirectory.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import logo from '../assets/kanka.png';
import { info } from '../logger';
import { logInfo } from '../logger';
import getSetting from '../module/getSettings';
import KankaSettings from '../types/KankaSettings';

let button: JQuery<HTMLButtonElement> | undefined;

export default async function renderJournalDirectory(app: JournalSheet, html: JQuery<HTMLDivElement>): Promise<void> {
if (!game.user.isGM) return;

info('renderJournalDirectory');
logInfo('renderJournalDirectory');

button = $(`
<button type="button" id="kanka">
Expand All @@ -15,8 +17,8 @@ export default async function renderJournalDirectory(app: JournalSheet, html: JQ
`);

button.on('click', () => {
if (!game.settings.get('kanka-foundry', 'access_token')) {
ui.notifications.error(game.i18n.localize('KANKA.ProvideAccessToken'));
if (!getSetting(KankaSettings.accessToken)) {
ui.notifications.error(game.i18n.localize('KANKA.ErrorProvideAccessToken'));
}

// Do actual stuff
Expand Down
4 changes: 2 additions & 2 deletions src/logger.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/* eslint-disable no-console */
import moduleConfig from './module.json';

export function info(...args: unknown[]): void {
export function logInfo(...args: unknown[]): void {
console.log(moduleConfig.name, ' | ', ...args);
}

export function error(...args: unknown[]): void {
export function logError(...args: unknown[]): void {
console.error(moduleConfig.name, ' | ', ...args);
}
91 changes: 91 additions & 0 deletions src/module/configureSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { logError } from '../logger';
import moduleConfig from '../module.json';
import KankaSettings from '../types/KankaSettings';
import getSettings from './getSettings';
import { getCampaigns } from './kanka';

const accessTokenInputName = `${moduleConfig.name}.${KankaSettings.accessToken}`;
const campaignInputName = `${moduleConfig.name}.${KankaSettings.campaign}`;

async function getCampaignChoices(token?: string): Promise<Record<string, string>> {
if (!token) {
return {
'': game.i18n.localize('KANKA.SettingsCampaignNoToken'),
};
}

try {
const campaignChoices: Record<string, string> = {
'': game.i18n.localize('KANKA.SettingsCampaignPleaseChoose'),
};
const campaignsResult = await getCampaigns(token);

campaignsResult.data.forEach((campaign) => {
campaignChoices[campaign.id] = campaign.name;
});

return campaignChoices;
} catch (error) {
logError(error);
return {
'': game.i18n.localize('KANKA.SettingsCampaignInvalidToken'),
};
}
}

async function updateWorldList(event: any): Promise<void> {
const token = event.target.value;
const choices = await getCampaignChoices(token);

const select = $(`[name="${campaignInputName}"]`);
select.empty();

Object.entries(choices).forEach(([value, label]) => {
const option = $(`<option value="${value}">${label}</option>`);
select.append(option);
});

select.val(getSettings(KankaSettings.campaign));
}

export function clearSettings(): void {
Array
.from<string>(game.settings.settings.keys())
.filter((key: string) => key.startsWith(moduleConfig.name))
.forEach(key => game.settings.settings.delete(key));

$(document).off('change', `[name="${accessTokenInputName}"]`, updateWorldList);
}

export async function registerSettings(): Promise<void> {
$(document).on('change', `[name="${accessTokenInputName}"]`, updateWorldList);

game.settings.register(
moduleConfig.name,
KankaSettings.accessToken,
{
name: game.i18n.localize('KANKA.SettingsTokenLabel'),
hint: game.i18n.localize('KANKA.SettingsTokenHint'),
scope: 'world',
config: true,
type: String,
default: '',
},
);

game.settings.register(
moduleConfig.name,
KankaSettings.campaign,
{
name: game.i18n.localize('KANKA.SettingsCampaignLabel'),
hint: game.i18n.localize('KANKA.SettingsCampaignHint'),
scope: 'world',
config: true,
type: String,
default: '',
choices: await getCampaignChoices(getSettings(KankaSettings.accessToken)),
},
);

game.settings.sheet.render(); // update sheet if it already visible
}
6 changes: 6 additions & 0 deletions src/module/getSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import moduleConfig from '../module.json';
import KankaSettings from '../types/KankaSettings';

export default function getSetting<T = unknown>(setting: KankaSettings): T {
return game.settings.get(moduleConfig.name, setting);
}
54 changes: 54 additions & 0 deletions src/module/kanka.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* eslint-disable @typescript-eslint/naming-convention */
import KankaSettings from '../types/KankaSettings';
import getSetting from './getSettings';

interface KankaLinks {
first: string;
last: string;
prev: string | null;
next: string | null
}

interface KankaMeta {
current_page: number;
from: number;
last_page: number;
path: string;
per_page: number;
to: number;
total: number;
}

interface KankaResult<T> {
data: T;
links: KankaLinks;
meta: KankaMeta;
}

interface CampaignData {
id: number;
name: string;
}

async function fetchKanka<T>(path: string, token?: string): Promise<T> {
const response = await fetch(
`https://kanka.io/api/1.0/${path}`,
{
mode: 'cors',
headers: {
Authorization: `Bearer ${token ?? getSetting<string>(KankaSettings.accessToken)}`,
'Content-type': 'application/json',
},
},
);

if (!response.ok) {
throw new Error(`Kanka request error: ${response.statusText} (${response.status})`);
}

return response.json();
}

export async function getCampaigns(token?: string): Promise<KankaResult<CampaignData[]>> {
return fetchKanka('campaigns', token);
}
53 changes: 0 additions & 53 deletions src/module/settings.ts

This file was deleted.

6 changes: 6 additions & 0 deletions src/types/KankaSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
enum KankaSettings {
accessToken = 'access_token',
campaign = 'campaign',
}

export default KankaSettings;
9 changes: 6 additions & 3 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,16 @@ module.exports = {
publicPath: `/modules/${moduleConfig.name}/`,
},
plugins: [
new CopyPlugin({ patterns: ['./src/module.json'] }),
new CopyPlugin({
patterns: [
'./src/module.json',
{ from: './src/lang', to: './lang' },
],
}),
new MiniCssExtractPlugin(),
],
devtool: 'cheap-module-source-map',
devServer: {
// contentBase: join(__dirname, 'dist'),
// compress: true,
inline: true,
port: 3000,
publicPath: `/modules/${moduleConfig.name}/`,
Expand Down

0 comments on commit 8732493

Please sign in to comment.