@polymindslabs/widget-sdk
Version:
Universal Job Widget SDK for embedding job boards and apply buttons
3 lines (2 loc) • 49.9 kB
JavaScript
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});class e{constructor(e){this.config=e}static init(n){e.instance=new e(n)}static getInstance(){return e.instance||(e.instance=new e({debug:!1})),e.instance}static updateConfig(n){e.instance&&(e.instance.config={...e.instance.config,...n})}static debug(e,...n){}static info(e,...n){}static warn(n,...t){const i=e.getInstance();if(i.config.debug){const e=i.config.prefix?`[${i.config.prefix}] `:"";console.warn(`${e}WARN: ${n}`,...t)}}static error(n,t){const i=e.getInstance(),o=i.config.prefix?`[${i.config.prefix}] `:"";i.config.debug?console.error(`${o}ERROR: ${n}`,t):console.error(`${o}ERROR: ${n}`)}static sanitize(n){if(!n||"object"!=typeof n)return n;const t=["password","token","key","secret","credential","auth","access_token","refresh_token","apiKey","clientId","clientSecret"],i=Array.isArray(n)?[]:{};for(const[o,s]of Object.entries(n)){const n=o.toLowerCase();t.some(e=>n.includes(e))?"string"==typeof s&&s.length>4?i[o]="****"+s.slice(-4):i[o]="****":i[o]="object"==typeof s&&null!==s?e.sanitize(s):s}return i}static debugSafe(n,t){if(e.getInstance().config.debug){const i=t?e.sanitize(t):void 0;e.debug(n,i)}}static logApiResponse(n,t){if(e.getInstance().config.debug){const i=e.sanitize(t);e.debug(n,i)}}static logAuth(n,t){if(e.getInstance().config.debug)if(t){const i={...t,access_token:t.access_token?"****"+t.access_token.slice(-4):void 0,expires_at:t.expires_at};e.debug(n,i)}else e.debug(n)}}e.debug,e.info,e.warn,e.error,e.debugSafe,e.logApiResponse,e.logAuth,e.sanitize;class n{constructor(n){this.config=n,this.baseUrl=n.baseUrl||"",this.headers={"Content-Type":"application/json"},n.apiKey&&n.tenantId&&(this.headers["X-API-Key"]=n.apiKey,this.headers["X-Tenant-ID"]=n.tenantId),e.init({debug:n.debug||!1,prefix:"APIClient"})}async request(e,n={}){try{const t=this.getStoredToken(),i={...this.headers,...n.headers||{}};t&&(i.Authorization=`Bearer ${t.access_token}`);const o=await fetch(`${this.baseUrl}${e}`,{...n,headers:i}),s=await o.json();if(!o.ok){if(401===o.status)throw this.clearStoredToken(),{code:"AUTH_REQUIRED",message:"Authentication required",details:s};if(428===o.status)throw{code:"PROFILE_INCOMPLETE",message:s.message||"Profile incomplete",details:s};if(409===o.status)return{success:!1,error:{code:"ALREADY_APPLIED",message:s.message||"Already applied to this job",details:s}};throw{code:"API_ERROR",message:s.message||"API request failed",details:s}}return void 0!==s.success&&void 0!==s.data?s:{success:!0,data:s}}catch(e){if(e.code)throw e;throw{code:"NETWORK_ERROR",message:e.message||"Network request failed",details:e}}}getStoredToken(){const e=sessionStorage.getItem("job_widget_token");if(!e)return null;try{const n=JSON.parse(e);return n.expires_at>Date.now()?n:(this.clearStoredToken(),null)}catch{return null}}storeToken(e){sessionStorage.setItem("job_widget_token",JSON.stringify(e))}clearStoredToken(){sessionStorage.removeItem("job_widget_token"),sessionStorage.removeItem("job_widget_state")}async exchangeCodeForToken(e,n){const t=await fetch(`${this.config.baseUrl}/auth/v1/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:e,client_id:this.getOAuthClientId(),redirect_uri:this.getOAuthRedirectUri()})});if(!t.ok){const e=await t.json();throw{code:"AUTH_FAILED",message:e.error_description||"Authentication failed",details:e}}const i=await t.json(),o={access_token:i.access_token,expires_at:Date.now()+1e3*i.expires_in,scope:i.scope?.split(" ")||["profile:basic","email"]};return this.storeToken(o),o}getOAuthClientId(){return this.config.clientId||""}getOAuthRedirectUri(){return this.config.redirectUri||`${window.location.origin}/oauth-callback`}async getJobs(e){const n=new URLSearchParams;e&&Object.entries(e).forEach(([e,t])=>{void 0!==t&&n.append(e,String(t))});const t=await this.request("/v1/jobs"+(n.toString()?`?${n}`:""));if(!t.success)throw t.error;return t.data}async getJob(e){const n=await this.request(`/v1/jobs/${e}`);if(!n.success)throw n.error;return n.data}async applyToJob(e,n,t){const i=this.getStoredToken();if(!i||i.expires_at<Date.now())throw this.clearStoredToken(),{code:"AUTH_REQUIRED",message:"Authentication required",details:null};const o=`/v1/jobs/${e}/applications`,s={Authorization:`Bearer ${i.access_token}`,"Content-Type":"application/json","X-Tenant-ID":n};try{const i=await fetch(`${this.baseUrl}${o}`,{method:"POST",headers:s,body:JSON.stringify(t||{})});if(401===i.status)throw this.clearStoredToken(),{code:"AUTH_EXPIRED",message:"Token expired, re-authentication required",details:null};if(428===i.status){const o=await i.json();return sessionStorage.setItem("job_widget_pending_application",JSON.stringify({jobId:e,tenantId:n,additionalData:t,returnUrl:window.location.href})),{profile_completeness:o.profile_completeness||0,minimum_required:o.minimum_required||50,profile_url:o.profile_url,missing_sections:o.missing_sections||[],message:o.message||"Please complete your profile to apply"}}if(409===i.status){const e=await i.json();return{status:"already_applied",message:e.message||e.detail||"You have already applied to this job"}}if(!i.ok){const e=await i.json();throw{code:"API_ERROR",message:e.message||e.detail||"Failed to submit application",details:e}}return await i.json()}catch(e){if(e.code)throw e;throw{code:"NETWORK_ERROR",message:`Failed to apply: ${e}`,details:e}}}async getUserProfile(){const e=await this.request("/v1/user/profile");if(!e.success)throw e.error;return e.data}async getApplicationStatus(e){const n=await this.request(`/v1/applications/${e}`);if(!n.success)throw n.error;return n.data}async getUserApplications(){const e=await this.request("/v1/user/applications");if(!e.success)throw e.error;return e.data}isAuthenticated(){return null!==this.getStoredToken()}getOAuthUrl(e){const n=new URLSearchParams({response_type:"code",client_id:this.getOAuthClientId(),redirect_uri:this.getOAuthRedirectUri(),scope:"profile:basic email",state:e});return`${this.config.baseUrl}/auth/v1/oauth/authorize?${n}`}clearStorage(){this.clearStoredToken(),sessionStorage.removeItem("job_widget_applied_jobs"),sessionStorage.removeItem("job_widget_state")}}class t{constructor(n){this.authWindow=null,this.authPromise=null,this.authResolver=null,this.authRejecter=null,this.checkInterval=null,this.config=n,this.setupMessageListener(),this.setupStorageListener(),e.init({debug:n.debug||!1,prefix:"OAuthHandler"})}setupMessageListener(){window.addEventListener("message",this.handleMessage.bind(this))}setupStorageListener(){window.addEventListener("storage",n=>{if("job_widget_token"===n.key&&n.newValue)try{const e=JSON.parse(n.newValue);e&&this.authResolver&&this.handleAuthSuccess(e)}catch(n){e.error("Failed to parse stored token",n)}})}async handleMessage(n){const t=window.location.origin,i=this.config.redirectUri?new URL(this.config.redirectUri).origin:t;if(n.origin===t||n.origin===i)if("JOB_WIDGET_OAUTH_CALLBACK"===n.data.type){if(!this.authResolver)return;const{code:t,state:i,error:o}=n.data;if(o)return e.error("OAuth error",o),void this.handleAuthError({code:"OAUTH_ERROR",message:o,details:null});if(i!==sessionStorage.getItem("job_widget_state"))return e.error("OAuth state mismatch"),void this.handleAuthError({code:"INVALID_STATE",message:"Invalid state parameter",details:null});try{const e=await this.exchangeCodeForToken(t);this.handleAuthSuccess(e)}catch(n){e.error("Token exchange failed",n),this.handleAuthError(n)}}else"job-widget-oauth-success"===n.data.type?this.handleAuthSuccess(n.data.token):"job-widget-oauth-error"===n.data.type&&this.handleAuthError(n.data.error)}async authenticate(){if(this.authPromise)return this.authPromise;const e=this.getStoredToken();return e&&e.expires_at>Date.now()?Promise.resolve(e):(e&&this.clearStoredToken(),this.authPromise=new Promise((e,n)=>{this.authResolver=e,this.authRejecter=n;const t=this.generateState();sessionStorage.setItem("job_widget_state",t);const i=this.buildOAuthUrl(t);!1!==this.config.usePopup?this.openPopup(i):window.location.href=i}),this.authPromise)}openPopup(e){const n=(window.screen.width-500)/2,t=(window.screen.height-700)/2;this.authWindow=window.open(e,"JobWidgetOAuth",`width=500,height=700,left=${n},top=${t},popup=yes`),this.authWindow?this.monitorPopup():this.handlePopupBlocked()}monitorPopup(){this.checkInterval=setInterval(()=>{if(!this.authWindow||this.authWindow.closed){this.cleanup();const e=this.getStoredToken();e?this.handleAuthSuccess(e):this.handleAuthCancelled()}},500)}handlePopupBlocked(){const e={code:"POPUP_BLOCKED",message:"Please enable popups to authenticate",details:{fallbackUrl:this.buildOAuthUrl(sessionStorage.getItem("job_widget_state")||"")}};this.authRejecter&&this.authRejecter(e),this.cleanup()}handleAuthSuccess(n){this.storeToken(n),this.authWindow&&!this.authWindow.closed&&this.authWindow.close(),this.authResolver?this.authResolver(n):e.warn("No auth resolver found!"),this.config.onAuthSuccess&&this.config.onAuthSuccess(n.access_token),this.cleanup()}handleAuthError(e){this.authRejecter&&this.authRejecter(e),this.config.onAuthRequired&&this.config.onAuthRequired(),this.cleanup()}handleAuthCancelled(){const e={code:"AUTH_CANCELLED",message:"Authentication was cancelled",details:null};this.authRejecter&&this.authRejecter(e),this.cleanup()}buildOAuthUrl(e){const n=new URLSearchParams({response_type:"code",client_id:this.getClientId(),redirect_uri:this.getRedirectUri(),scope:"profile:basic email",state:e});this.config.tenantId&&n.append("tenant_id",this.config.tenantId);return`${this.config.baseUrl}/auth/v1/oauth/authorize?${n}`}getClientId(){return this.config.clientId||""}getRedirectUri(){return this.config.redirectUri?this.config.redirectUri:`${window.location.origin}/oauth-callback`}async exchangeCodeForToken(e){const n=this.config.baseUrl,t=await fetch(`${n}/auth/v1/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:e,client_id:this.getClientId(),redirect_uri:this.getRedirectUri()})});if(!t.ok){const e=await t.text();throw new Error(`Token exchange failed: ${e}`)}const i=await t.json();return{access_token:i.access_token,expires_at:Date.now()+1e3*(i.expires_in||3600),scope:i.scope?i.scope.split(" "):["profile:basic","email"]}}generateState(){return Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15)}getStoredToken(){const e=sessionStorage.getItem("job_widget_token");if(!e)return null;try{const n=JSON.parse(e);return n.expires_at>Date.now()?n:(this.clearStoredToken(),null)}catch{return null}}storeToken(e){sessionStorage.setItem("job_widget_token",JSON.stringify(e))}clearStoredToken(){sessionStorage.removeItem("job_widget_token"),sessionStorage.removeItem("job_widget_state")}cleanup(){this.authPromise=null,this.authResolver=null,this.authRejecter=null,this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=null),this.authWindow=null}destroy(){this.cleanup(),window.removeEventListener("message",this.handleMessage.bind(this))}}class i{constructor(){this.events=new Map}on(e,n){this.events.has(e)||this.events.set(e,new Set),this.events.get(e).add(n)}addEventListener(e,n){this.on(e,n)}off(e,n){const t=this.events.get(e);t&&(t.delete(n),0===t.size&&this.events.delete(e))}removeEventListener(e,n){this.off(e,n)}once(e,n){const t=i=>{n(i),this.off(e,t)};this.on(e,t)}emit(n,t){const i=this.events.get(n);i&&i.forEach(i=>{try{i(t)}catch(t){e.error(`Error in event handler for ${n}`,t)}})}removeAllListeners(e){e?this.events.delete(e):this.events.clear()}listenerCount(e){const n=this.events.get(e);return n?n.size:0}eventNames(){return Array.from(this.events.keys())}}class o{static handleCallback(){const e=new URLSearchParams(window.location.search),n=e.get("code"),t=e.get("state"),i=e.get("error");if(window.opener)window.opener.postMessage({type:"JOB_WIDGET_OAUTH_CALLBACK",code:n,state:t,error:i},window.location.origin),window.close();else{if(n&&t){t===sessionStorage.getItem("job_widget_state")&&sessionStorage.setItem("job_widget_oauth_code",n)}const e=sessionStorage.getItem("job_widget_return_url")||"/";window.location.href=e}}static renderCallbackPage(){document.body.innerHTML='\n <div style="\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n ">\n <div style="\n background: white;\n padding: 40px;\n border-radius: 12px;\n box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);\n text-align: center;\n max-width: 400px;\n ">\n <div style="\n width: 60px;\n height: 60px;\n margin: 0 auto 20px;\n background: #10b981;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n ">\n <svg width="30" height="30" viewBox="0 0 24 24" fill="white">\n <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/>\n </svg>\n </div>\n <h2 style="margin: 0 0 10px; color: #111827;">Authentication Successful</h2>\n <p style="color: #6b7280; margin: 0;">This window will close automatically...</p>\n </div>\n </div>\n ',setTimeout(()=>{o.handleCallback()},100)}}class s extends i{constructor(i){super(),this.container=null,this.initialized=!1,this.validateConfig(i),this.config=this.mergeWithDefaults(i),e.init({debug:this.config.debug||!1,prefix:"JobWidget"}),this.apiClient=new n(this.config),this.oauthHandler=new t(this.config),this.state={initialized:!1,loading:!1,error:null,user:null,jobs:[],selectedJob:null,applications:[],config:this.config},this.setupContainer()}validateConfig(e){const n=[];if(e.container||n.push("container is required"),e.tenantId||n.push("tenantId is required for fetching jobs"),e.apiKey||n.push("apiKey is required for API authentication"),e.clientId||n.push("clientId is required for job applications"),e.redirectUri||n.push("redirectUri is required for OAuth authentication"),e.baseUrl||n.push("baseUrl is required for API and OAuth endpoints"),n.length>0)throw new Error(`Missing required parameters:\n${n.map(e=>`- ${e}`).join("\n")}\n\nExample usage:\nnew JobWidget({\n container: '#widget',\n tenantId: 'your-tenant-id',\n apiKey: 'your-api-key',\n clientId: 'your-oauth-client-id',\n redirectUri: 'https://yoursite.com/oauth-callback',\n baseUrl: 'https://api.yourservice.com'\n});`)}mergeWithDefaults(e){const n={theme:e.theme||"light",type:e.type||"job-list",responsive:!1!==e.responsive,usePopup:!1!==e.usePopup,showLogo:!1!==e.showLogo,showPoweredBy:!1!==e.showPoweredBy,profileCompletionRequired:e.profileCompletionRequired||50,locale:e.locale||"en-US",debug:e.debug||!1,sandbox:e.sandbox||!1,version:e.version||"v1"};return e.clientId&&(n.redirectUri=e.redirectUri||`${window.location.origin}/job-widget/callback`),{...e,...n}}setupContainer(){if("string"==typeof this.config.container){if(this.container=document.querySelector(this.config.container),!this.container)throw new Error(`Container element not found: ${this.config.container}`)}else this.container=this.config.container;this.container.classList.add("job-widget"),this.container.classList.add(`job-widget-${this.config.type}`),this.config.theme&&this.container.classList.add(`job-theme-${this.config.theme}`),this.config.responsive&&this.container.classList.add("inzif-responsive")}async init(){if(!this.initialized)try{this.emit("init",void 0),this.updateState({loading:!0}),await this.loadStyles(),await this.render(),this.initialized=!0,this.updateState({initialized:!0,loading:!1}),this.emit("ready",void 0),this.config.onReady&&this.config.onReady()}catch(e){this.handleError(e)}}async loadStyles(){if(document.querySelector("#inzif-widget-styles"))return;const e=document.createElement("style");if(e.id="inzif-widget-styles",e.textContent="\n .inzif-widget {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n color: #374151;\n line-height: 1.5;\n }\n .inzif-job-list {\n padding: 20px;\n }\n .inzif-job-item {\n background: #ffffff;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n padding: 24px;\n margin-bottom: 20px;\n transition: box-shadow 0.2s, transform 0.2s;\n }\n .inzif-job-item:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n }\n .inzif-job-header {\n display: flex;\n gap: 16px;\n margin-bottom: 16px;\n }\n .inzif-company-logo {\n width: 64px;\n height: 64px;\n border-radius: 8px;\n object-fit: contain;\n background: #f9fafb;\n padding: 8px;\n }\n .inzif-job-main {\n flex: 1;\n }\n .inzif-job-title {\n margin: 0 0 4px;\n font-size: 20px;\n font-weight: 600;\n color: #111827;\n }\n .inzif-company-name {\n margin: 0 0 12px;\n font-size: 16px;\n color: #6b7280;\n }\n .inzif-job-meta {\n display: flex;\n flex-wrap: wrap;\n gap: 16px;\n margin-bottom: 16px;\n }\n .inzif-meta-item {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: #6b7280;\n }\n .inzif-meta-item svg {\n color: #9ca3af;\n }\n .inzif-job-description {\n margin: 16px 0;\n padding: 16px;\n background: #f9fafb;\n border-radius: 8px;\n }\n .inzif-description-text {\n margin: 0;\n font-size: 14px;\n color: #4b5563;\n white-space: pre-wrap;\n }\n .inzif-expand-btn {\n margin-top: 8px;\n padding: 6px 12px;\n background: transparent;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n font-size: 14px;\n color: #6b7280;\n cursor: pointer;\n transition: all 0.2s;\n }\n .inzif-expand-btn:hover {\n background: #ffffff;\n border-color: #9ca3af;\n color: #374151;\n }\n .inzif-salary-range {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin: 12px 0;\n padding: 8px 16px;\n background: #ecfdf5;\n color: #065f46;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n }\n .inzif-salary-range svg {\n color: #059669;\n }\n .inzif-job-actions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 20px;\n padding-top: 20px;\n border-top: 1px solid #e5e7eb;\n }\n .inzif-apply-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 10px 24px;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n border-radius: 8px;\n font-size: 16px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.3s ease;\n min-width: 160px;\n }\n .inzif-apply-button:hover:not(:disabled) {\n transform: translateY(-2px);\n box-shadow: 0 8px 16px rgba(102, 126, 234, 0.4);\n }\n .inzif-apply-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n .inzif-apply-button.already-applied {\n background: linear-gradient(135deg, #e2e8f0 0%, #cbd5e0 100%);\n color: #4a5568;\n cursor: default;\n position: relative;\n }\n .inzif-apply-button.already-applied::before {\n content: '✓';\n position: absolute;\n left: 12px;\n font-size: 18px;\n color: #48bb78;\n font-weight: bold;\n }\n .inzif-deadline {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: #dc2626;\n }\n .inzif-deadline svg {\n color: #ef4444;\n }\n\n /* Widget Footer Styles */\n .inzif-widget-footer {\n margin-top: 32px;\n padding-top: 24px;\n border-top: 1px solid #e5e7eb;\n font-size: 14px;\n color: #6b7280;\n animation: fadeIn 0.5s ease-out;\n }\n .inzif-footer-content {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 12px;\n }\n .inzif-footer-branding {\n font-weight: 500;\n }\n .inzif-powered-by a {\n color: #6366f1;\n text-decoration: none;\n font-weight: 600;\n transition: color 0.2s;\n }\n .inzif-powered-by a:hover {\n color: #4f46e5;\n text-decoration: underline;\n }\n .inzif-footer-links {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n .inzif-footer-links a {\n color: #6b7280;\n text-decoration: none;\n transition: color 0.2s;\n }\n .inzif-footer-links a:hover {\n color: #374151;\n text-decoration: underline;\n }\n .inzif-footer-separator {\n color: #d1d5db;\n }\n .inzif-footer-copyright {\n text-align: center;\n font-size: 13px;\n color: #9ca3af;\n padding-top: 12px;\n }\n\n /* Loading Skeleton Styles */\n .inzif-skeleton {\n animation: skeleton-loading 1.2s linear infinite;\n background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);\n background-size: 200% 100%;\n border-radius: 8px;\n }\n .inzif-skeleton-job {\n height: 180px;\n margin-bottom: 20px;\n }\n @keyframes skeleton-loading {\n 0% { background-position: -200px 0; }\n 100% { background-position: calc(200px + 100%) 0; }\n }\n\n /* Smooth Animations */\n @keyframes fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n }\n @keyframes slideUp {\n from { opacity: 0; transform: translateY(20px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .inzif-job-item {\n animation: slideUp 0.4s ease-out;\n animation-fill-mode: both;\n }\n .inzif-job-item:nth-child(1) { animation-delay: 0.1s; }\n .inzif-job-item:nth-child(2) { animation-delay: 0.2s; }\n .inzif-job-item:nth-child(3) { animation-delay: 0.3s; }\n .inzif-job-item:nth-child(4) { animation-delay: 0.4s; }\n .inzif-job-item:nth-child(5) { animation-delay: 0.5s; }\n\n /* Empty State */\n .inzif-empty-state {\n text-align: center;\n padding: 60px 20px;\n color: #6b7280;\n }\n .inzif-empty-icon {\n width: 64px;\n height: 64px;\n margin: 0 auto 16px;\n opacity: 0.5;\n }\n .inzif-empty-title {\n font-size: 18px;\n font-weight: 600;\n color: #374151;\n margin-bottom: 8px;\n }\n .inzif-empty-message {\n font-size: 14px;\n color: #9ca3af;\n }\n\n /* Error State */\n .inzif-error-state {\n text-align: center;\n padding: 40px 20px;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 12px;\n margin: 20px;\n }\n .inzif-error-icon {\n width: 48px;\n height: 48px;\n margin: 0 auto 16px;\n color: #ef4444;\n }\n .inzif-error-title {\n font-size: 16px;\n font-weight: 600;\n color: #991b1b;\n margin-bottom: 8px;\n }\n .inzif-error-message {\n font-size: 14px;\n color: #b91c1c;\n margin-bottom: 16px;\n }\n .inzif-retry-button {\n padding: 8px 20px;\n background: #ef4444;\n color: white;\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.2s;\n }\n .inzif-retry-button:hover {\n background: #dc2626;\n }\n\n /* Responsive Design */\n @media (max-width: 640px) {\n .inzif-job-header {\n flex-direction: column;\n }\n .inzif-company-logo {\n width: 48px;\n height: 48px;\n }\n .inzif-job-meta {\n flex-direction: column;\n gap: 8px;\n }\n .inzif-job-actions {\n flex-direction: column;\n gap: 12px;\n }\n .inzif-apply-button {\n width: 100%;\n }\n .inzif-footer-content {\n flex-direction: column;\n gap: 12px;\n text-align: center;\n }\n .inzif-footer-links {\n order: 2;\n }\n .inzif-footer-branding {\n order: 1;\n }\n }\n ",document.head.appendChild(e),this.config.baseUrl){const e=document.createElement("link");e.rel="stylesheet",e.href=`${this.config.baseUrl}/assets/styles.css`,document.head.appendChild(e)}if(this.config.customStyles){const e=document.createElement("style");e.id="inzif-widget-custom-styles",e.textContent=this.config.customStyles,document.head.appendChild(e)}if(this.config.fontFamily){const e=document.createElement("style");e.textContent=`.inzif-widget { font-family: ${this.config.fontFamily}; }`,document.head.appendChild(e)}if(this.config.primaryColor){const e=document.createElement("style");e.textContent=`:root { --inzif-primary: ${this.config.primaryColor}; --inzif-primary-dark: ${this.darkenColor(this.config.primaryColor,20)}; }`,document.head.appendChild(e)}}darkenColor(e,n){const t=parseInt(e.replace("#",""),16),i=Math.round(2.55*n),o=(t>>16)-i,s=(t>>8&255)-i,a=(255&t)-i;return"#"+(16777216+65536*(o<255?o<1?0:o:255)+256*(s<255?s<1?0:s:255)+(a<255?a<1?0:a:255)).toString(16).slice(1)}async loadUserProfile(){try{const e=await this.apiClient.getUserProfile();this.updateState({user:e})}catch(n){e.debugSafe("User not authenticated",n)}}async disconnect(){this.apiClient.clearStorage(),this.updateState({user:null,applications:[]}),this.emit("auth:disconnect",void 0),this.config.onDisconnect&&this.config.onDisconnect(),await this.render()}async render(){this.container&&await this.renderJobList()}async renderJobList(){try{this.showLoadingSkeleton();const n=await this.apiClient.getJobs(),t=n.jobs||n.items||[];if(!Array.isArray(t))throw e.error("Jobs list is not an array"),new Error("Invalid response format - expected jobs array");this.updateState({jobs:t}),this.container.innerHTML="";const i=document.createElement("div");if(i.className="inzif-job-list",0===t.length){const e=this.createEmptyState();this.container.appendChild(e);const n=this.createWidgetFooter();return void this.container.appendChild(n)}t.forEach(e=>{const n=this.createJobItem(e);i.appendChild(n)}),this.container.appendChild(i);const o=this.createWidgetFooter();this.container.appendChild(o)}catch(e){this.showErrorState(e)}}createJobItem(e){const n=document.createElement("div");n.className="inzif-job-item";const t=(e,n=200)=>!e||e.length<=n?e:e.substring(0,n)+"...";var i,o;n.innerHTML=`\n <div class="inzif-job-header">\n ${e.company_logo?`<img src="${e.company_logo}" alt="${e.company_name||"Company"}" class="inzif-company-logo">`:""}\n <div class="inzif-job-main">\n <h3 class="inzif-job-title">${e.title}</h3>\n ${e.company_name?`<p class="inzif-company-name">${e.company_name}</p>`:""}\n <div class="inzif-job-meta">\n ${e.department?`<span class="inzif-meta-item"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 7h-9m0 10h9m-15-6a2 2 0 1 0 4 0 2 2 0 1 0-4 0m0-8a2 2 0 1 0 4 0 2 2 0 1 0-4 0m0 16a2 2 0 1 0 4 0 2 2 0 1 0-4 0"/></svg>${e.department}</span>`:""}\n ${e.location?`<span class="inzif-meta-item"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 1 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>${e.location}${e.is_remote?" (Remote Available)":""}</span>`:""}\n ${e.employment_type?`<span class="inzif-meta-item"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="7" width="20" height="14" rx="2" ry="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/></svg>${o=e.employment_type,{full_time:"Full Time",part_time:"Part Time",contract:"Contract",internship:"Internship",temporary:"Temporary"}[o]||o}</span>`:""}\n ${e.experience_level?`<span class="inzif-meta-item"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v20M2 12h20"/></svg>${i=e.experience_level,{fresher:"Fresher",entry:"Entry Level",mid:"Mid Level",senior:"Senior",lead:"Lead",manager:"Manager"}[i]||i}</span>`:""}\n </div>\n </div>\n </div>\n ${e.description?`\n <div class="inzif-job-description" data-expanded="false">\n <p class="inzif-description-text">${t(e.description)}</p>\n ${e.description.length>200?`\n <button class="inzif-expand-btn" data-job-id="${e.id}">\n Show more\n </button>\n `:""}\n </div>\n `:""}\n ${e.salary_min||e.salary_max?`\n <div class="inzif-salary-range">\n <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>\n ${e.salary_min&&e.salary_max?`${e.salary_currency||"$"}${e.salary_min.toLocaleString()} - ${e.salary_currency||"$"}${e.salary_max.toLocaleString()}`:e.salary_min?`From ${e.salary_currency||"$"}${e.salary_min.toLocaleString()}`:`Up to ${e.salary_currency||"$"}${e.salary_max?.toLocaleString()}`}\n </div>\n `:""}\n <div class="inzif-job-actions">\n <button class="inzif-apply-button ${this.hasAppliedToJob(e.id)?"already-applied":""}"\n data-job-id="${e.id}"\n ${this.hasAppliedToJob(e.id)?"disabled":""}>\n ${this.getButtonText(e.id)}\n </button>\n ${e.application_deadline?`\n <span class="inzif-deadline">\n <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>\n Apply by ${new Date(e.application_deadline).toLocaleDateString()}\n </span>\n `:""}\n </div>\n `;n.querySelector(".inzif-apply-button").onclick=()=>this.handleApply(e);const s=n.querySelector(".inzif-expand-btn");return s&&e.description&&(s.onclick=()=>{const i=n.querySelector(".inzif-job-description"),o=n.querySelector(".inzif-description-text");"true"===i.getAttribute("data-expanded")?(o.textContent=t(e.description),s.textContent="Show more",i.setAttribute("data-expanded","false")):(o.textContent=e.description,s.textContent="Show less",i.setAttribute("data-expanded","true"))}),n}showLoadingSkeleton(){this.container&&(this.container.innerHTML='\n <div class="inzif-job-list">\n <div class="inzif-skeleton inzif-skeleton-job"></div>\n <div class="inzif-skeleton inzif-skeleton-job"></div>\n <div class="inzif-skeleton inzif-skeleton-job"></div>\n </div>\n ')}createEmptyState(){const e=document.createElement("div");return e.className="inzif-empty-state",e.innerHTML='\n <svg class="inzif-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/>\n <path d="m3.3 7 8.7 5 8.7-5"/>\n <path d="M12 22V12"/>\n </svg>\n <h3 class="inzif-empty-title">No Positions Available</h3>\n <p class="inzif-empty-message">Check back soon for new opportunities!</p>\n ',e}showErrorState(e){if(!this.container)return;const n=document.createElement("div");n.className="inzif-error-state";const t=e.message||"Something went wrong while loading jobs";n.innerHTML=`\n <svg class="inzif-error-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <circle cx="12" cy="12" r="10"/>\n <path d="m15 9-6 6"/>\n <path d="m9 9 6 6"/>\n </svg>\n <h3 class="inzif-error-title">Unable to Load Jobs</h3>\n <p class="inzif-error-message">${t}</p>\n <button class="inzif-retry-button" onclick="window.location.reload()">\n Try Again\n </button>\n `,this.container.innerHTML="",this.container.appendChild(n);const i=this.createWidgetFooter();this.container.appendChild(i),this.handleError(e)}createWidgetFooter(){const e=document.createElement("div");e.className="inzif-widget-footer";const n=(new Date).getFullYear(),t=this.apiClient.isAuthenticated();if(e.innerHTML=`\n <div class="inzif-footer-content">\n <div class="inzif-footer-branding">\n <span class="inzif-powered-by">\n Powered by <a href="https://inzif.com" target="_blank" rel="noopener noreferrer">Inzif</a>\n </span>\n </div>\n <div class="inzif-footer-links">\n <a href="https://inzif.com/terms" target="_blank" rel="noopener noreferrer">Terms</a>\n <span class="inzif-footer-separator">•</span>\n <a href="https://inzif.com/privacy" target="_blank" rel="noopener noreferrer">Privacy</a>\n ${t?'\n <span class="inzif-footer-separator">•</span>\n <a href="#" class="inzif-disconnect-footer-link">Disconnect</a>\n ':""}\n </div>\n </div>\n <div class="inzif-footer-copyright">\n © ${n} Inzif. All rights reserved.\n </div>\n `,t){const n=e.querySelector(".inzif-disconnect-footer-link");n&&n.addEventListener("click",async e=>{e.preventDefault(),await this.disconnect()})}return e}async applyToJob(e,n,t){if(this.hasAppliedToJob(e)){const e={code:"ALREADY_APPLIED",message:"You have already applied to this job"};throw this.handleError(e),e}const i=await this.apiClient.applyToJob(e,n,t);if("profile_completeness"in i)return sessionStorage.setItem("job_widget_pending_application",JSON.stringify({jobId:e,tenantId:n,data:t})),this.showProfileCompletionModal(i),i;const o=i;return this.markJobAsApplied(e),this.emit("apply:success",o),this.config.onSuccess&&this.config.onSuccess(o),this.storeApplication(o),this.showSuccessMessage(),o}async handleApply(e){try{e&&this.updateState({selectedJob:e});const n=e||this.state.selectedJob;if(!n)throw new Error("No job selected");if(this.hasAppliedToJob(n.id))return void this.showInfoMessage("You have already applied to this job");this.emit("apply:start",n),this.config.onApply&&this.config.onApply(n);let t=0;const i=1;for(;t<=i;)try{this.apiClient.isAuthenticated()||await this.authenticate();const e=this.config.tenantId||"",t=await this.apiClient.applyToJob(n.id,e);if("status"in t&&"already_applied"===t.status)return this.markJobAsApplied(n.id),void this.showInfoMessage("You have already applied to this job");if("profile_completeness"in t)return void this.showProfileCompletionModal(t);const i=t;return this.markJobAsApplied(n.id),this.emit("apply:success",i),this.config.onSuccess&&this.config.onSuccess(i),this.storeApplication(i),void this.showSuccessMessage()}catch(e){const n=e;if("AUTH_EXPIRED"===n.code&&t<i){t++,await this.authenticate();continue}if("AUTH_REQUIRED"===n.code&&t<i){t++,await this.authenticate();continue}throw n}}catch(e){const n=e;this.emit("apply:failed",n),this.handleError(n)}}async authenticate(){try{this.emit("auth:required",void 0),this.config.onAuthRequired&&this.config.onAuthRequired();const e=await this.oauthHandler.authenticate();this.emit("auth:success",e),await this.render(),await this.resumePendingApplication()}catch(e){const n=e;throw this.emit("auth:failed",n),n}}handleProfileIncomplete(e){this.emit("profile:incomplete",e),this.config.onProfileIncomplete&&this.config.onProfileIncomplete(e),this.showProfileIncompleteMessage(e)}showSuccessMessage(){const e=document.createElement("div");e.className="inzif-message inzif-success",e.textContent=this.getTranslation("application_success"),document.body.appendChild(e),setTimeout(()=>{e.remove()},5e3)}showInfoMessage(e){const n=document.createElement("div");n.className="inzif-message inzif-info",n.textContent=e,document.body.appendChild(n),setTimeout(()=>{n.remove()},5e3)}showProfileIncompleteMessage(e){const n=document.createElement("div");n.className="inzif-message inzif-warning",n.innerHTML=`\n <p>${e.message}</p>\n <a href="${e.profile_url}" target="_blank" class="inzif-profile-link">\n ${this.getTranslation("complete_profile")}\n </a>\n `,this.container.appendChild(n)}showProfileCompletionModal(e){const n=document.getElementById("inzif-profile-modal");n&&n.remove();const t=Math.round(e.profile_completeness||0),i=Math.round(e.minimum_required||50),o=(e.missing_sections||[]).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(", ")||"Profile details",s=document.createElement("div");s.id="inzif-profile-modal",s.className="inzif-profile-modal",s.innerHTML=`\n <div class="inzif-modal-overlay"></div>\n <div class="inzif-modal-content">\n <div class="inzif-modal-header">\n <h3>Complete Your Profile to Apply</h3>\n <button class="inzif-modal-close" aria-label="Close">×</button>\n </div>\n <div class="inzif-modal-body">\n <p class="inzif-modal-message">\n Your profile is <strong>${t}% complete</strong>.\n This position requires a minimum of <strong>${i}%</strong> profile completion.\n </p>\n\n <div class="inzif-progress-container">\n <div class="inzif-progress-bar">\n <div class="inzif-progress-fill" style="width: ${t}%"></div>\n <div class="inzif-progress-required" style="left: ${i}%"></div>\n </div>\n <div class="inzif-progress-labels">\n <span class="current">${t}%</span>\n <span class="required">Required: ${i}%</span>\n </div>\n </div>\n\n <div class="inzif-missing-sections">\n <p><strong>Complete these sections:</strong></p>\n <p class="sections">${o}</p>\n </div>\n\n <div class="inzif-modal-guidance">\n <p>✨ It only takes a few minutes to complete your profile and apply for this position!</p>\n </div>\n </div>\n <div class="inzif-modal-footer">\n <button class="inzif-btn-secondary" id="inzif-cancel-btn">\n Maybe Later\n </button>\n <button class="inzif-btn-primary" id="inzif-complete-profile-btn">\n Complete Profile →\n </button>\n </div>\n </div>\n `,this.addModalStyles(),document.body.appendChild(s);const a=s.querySelector(".inzif-modal-close"),r=s.querySelector("#inzif-cancel-btn"),c=s.querySelector("#inzif-complete-profile-btn"),l=s.querySelector(".inzif-modal-overlay"),d=()=>{s.classList.add("closing"),setTimeout(()=>s.remove(),300)};a.onclick=d,r.onclick=d,l.onclick=d,c.onclick=n=>{n.preventDefault();const t=window.open(e.profile_url||"https://inzif.com/profile","_blank","noopener,noreferrer");if(!t||t.closed){const n=document.createElement("a");n.href=e.profile_url||"https://inzif.com/profile",n.target="_blank",n.rel="noopener noreferrer",n.className="inzif-btn-primary",n.textContent="Open Profile in New Tab →",n.style.textDecoration="none",n.style.display="inline-block",c.replaceWith(n)}else c.textContent="Profile Opened ✓",c.style.background="#48bb78",c.disabled=!0,setTimeout(()=>{d(),this.showInfoMessage("Complete your profile in the new tab, then click Apply again!")},1500)},setTimeout(()=>s.classList.add("show"),10)}addModalStyles(){if(document.getElementById("inzif-modal-styles"))return;const e=document.createElement("style");e.id="inzif-modal-styles",e.textContent="\n #inzif-profile-modal {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999999;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n .inzif-modal-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n animation: fadeIn 0.3s ease;\n }\n .inzif-modal-content {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: white;\n border-radius: 12px;\n box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);\n max-width: 480px;\n width: 90%;\n max-height: 90vh;\n overflow: auto;\n animation: slideIn 0.3s ease;\n }\n .inzif-modal-header {\n padding: 24px;\n border-bottom: 1px solid #e5e7eb;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .inzif-modal-header h3 {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #111827;\n }\n .inzif-modal-close {\n background: none;\n border: none;\n font-size: 24px;\n color: #6b7280;\n cursor: pointer;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n transition: all 0.2s;\n }\n .inzif-modal-close:hover {\n background: #f3f4f6;\n color: #111827;\n }\n .inzif-modal-body {\n padding: 24px;\n }\n .inzif-progress-container {\n position: relative;\n height: 24px;\n background: #f3f4f6;\n border-radius: 12px;\n overflow: hidden;\n margin-bottom: 20px;\n }\n .inzif-progress-bar {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n background: linear-gradient(90deg, #3b82f6, #6366f1);\n border-radius: 12px;\n transition: width 0.3s ease;\n }\n .inzif-progress-text {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n font-size: 12px;\n font-weight: 600;\n color: #374151;\n }\n .inzif-modal-message {\n font-size: 14px;\n color: #6b7280;\n margin: 0 0 20px;\n line-height: 1.5;\n }\n .inzif-missing-fields {\n background: #fef3c7;\n border: 1px solid #fcd34d;\n border-radius: 8px;\n padding: 16px;\n }\n .inzif-missing-fields h4 {\n margin: 0 0 8px;\n font-size: 14px;\n font-weight: 600;\n color: #92400e;\n }\n .inzif-missing-fields ul {\n margin: 0;\n padding-left: 20px;\n }\n .inzif-missing-fields li {\n font-size: 14px;\n color: #92400e;\n margin: 4px 0;\n }\n .inzif-modal-footer {\n padding: 24px;\n border-top: 1px solid #e5e7eb;\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n }\n .inzif-btn {\n padding: 10px 20px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s;\n border: none;\n outline: none;\n }\n .inzif-btn-primary {\n background: #3b82f6;\n color: white;\n }\n .inzif-btn-primary:hover {\n background: #2563eb;\n }\n .inzif-btn-secondary {\n background: #f3f4f6;\n color: #374151;\n }\n .inzif-btn-secondary:hover {\n background: #e5e7eb;\n }\n @keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes slideIn {\n from {\n opacity: 0;\n transform: translate(-50%, -48%);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%);\n }\n }\n ",document.head.appendChild(e)}hasAppliedToJob(e){return this.getAppliedJobs().includes(e)}getButtonText(e){return this.hasAppliedToJob(e)?"Already Applied":this.apiClient.isAuthenticated()?"Apply Now":"Apply with Inzif"}markJobAsApplied(e){const n=this.getAppliedJobs();n.includes(e)||(n.push(e),sessionStorage.setItem("job_widget_applied_jobs",JSON.stringify(n)))}getAppliedJobs(){const e=sessionStorage.getItem("job_widget_applied_jobs");return e?JSON.parse(e):[]}storeApplication(e){const n=this.getStoredApplications();n.push(e),sessionStorage.setItem("job_widget_applications",JSON.stringify(n))}getStoredApplications(){const e=sessionStorage.getItem("job_widget_applications");return e?JSON.parse(e):[]}updateState(e){this.state={...this.state,...e}}handleError(n){this.updateState({error:n,loading:!1}),this.emit("error",n),this.config.onError&&this.config.onError(n),e.error("Job Widget Error",n)}getTranslation(e){return{apply:"Apply",apply_now:"Apply Now",application_success:"Application submitted successfully!",complete_profile:"Complete Your Profile",profile_incomplete:"Profile Incomplete",missing_fields:"Missing Fields",cancel:"Cancel",...this.config.translations}[e]||e}getState(){return{...this.state}}createButton(e,n,t){const i="string"==typeof e?document.querySelector(e):e;if(!i)throw new Error("Button container element not found");const o=document.createElement("button");return o.className=t?.className||"inzif-apply-button",o.textContent=t?.text||this.getTranslation("apply_now"),o.onclick=async()=>{try{const e=this.config.tenantId||"",i=await this.applyToJob(n,e);t?.onSuccess&&t.onSuccess(i)}catch(e){t?.onError&&t.onError(e)}},i.appendChild(o),o}getToken(){const e=sessionStorage.getItem("job_widget_token");if(!e)return sessionStorage.getItem("job_widget_access_token");try{const n=JSON.parse(e);if(n.expires_at>Date.now())return n.access_token}catch{return sessionStorage.getItem("job_widget_access_token")}return null}static handleOAuthCallback(){o.renderCallbackPage()}static handleCallback(){const e=new URLSearchParams(window.location.search),n=e.get("code"),t=e.get("state"),i=e.get("error");if(i)window.opener&&window.opener.postMessage({type:"JOB_WIDGET_OAUTH_CALLBACK",error:i},window.location.origin);else if(n&&t){if(t===sessionStorage.getItem("job_widget_state"))if(window.opener)window.opener.postMessage({type:"JOB_WIDGET_OAUTH_CALLBACK",code:n,state:t},window.location.origin),window.close();else{sessionStorage.setItem("job_widget_oauth_code",n);const e=sessionStorage.getItem("job_widget_return_url");e&&(window.location.href=e)}}}generateState(){return Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15)}createButtons(n){const t=[];return n.forEach(n=>{const i="string"==typeof n.container?document.querySelector(n.container):n.container;if(!i)return void e.warn(`Button container not found: ${n.container}`);const o=document.createElement("button");o.className=n.className||"inzif-apply-button",o.textContent=n.text||this.getTranslation("apply_now"),o.onclick=async()=>{try{const e=n.tenantId||this.config.tenantId||"",t=await this.applyToJob(n.jobId,e);n.onSuccess&&n.onSuccess(t)}catch(e){n.onError&&n.onError(e)}},i.appendChild(o),t.push(o)}),t}async resumePendingApplication(){const n=sessionStorage.getItem("job_widget_pending_application");if(n)try{const e=JSON.parse(n);sessionStorage.removeItem("job_widget_pending_application"),await this.applyToJob(e.jobId,e.tenantId,e.data)}catch(n){e.error("Failed to resume pending application",n)}}destroy(){this.removeAllListeners(),this.oauthHandler.destroy(),this.container&&(this.container.innerHTML="",this.container.classList.remove("inzif-widget")),this.initialized=!1}}"undefined"!=typeof window&&"undefined"!=typeof document&&(window.JobWidget=s,window.location.pathname.includes("/oauth-callback")?s.handleOAuthCallback():"/job-widget/callback"===window.location.pathname&&s.handleCallback(),window.initJobWidget=async e=>{const n=new s(e);return await n.init(),n},document.addEventListener("DOMContentLoaded",()=>{const n=document.currentScript||document.querySelector("script[data-job-widget]");if(n&&n.hasAttribute("data-job-widget")){const t={container:n.getAttribute("data-container")||"#job-widget",tenantId:n.getAttribute("data-tenant-id"),apiKey:n.getAttribute("data-api-key"),clientId:n.getAttribute("data-client-id"),redirectUri:n.getAttribute("data-redirect-uri"),type:n.getAttribute("data-widget-type")||"job-list",apiUrl:n.getAttribute("data-api-url"),theme:n.getAttribute("data-theme"),primaryColor:n.getAttribute("data-primary-color"),locale:n.getAttribute("data-locale")};Object.keys(t).forEach(e=>{null!==t[e]&&void 0!==t[e]||delete t[e]}),t.tenantId&&t.apiKey&&t.clientId&&t.redirectUri&&window.initJobWidget(t).catch(n=>{e.error("Failed to initialize job widget",n)})}})),exports.APIClient=n,exports.EventEmitter=i,exports.JobWidget=s,exports.Logger=e,exports.OAuthHandler=t,exports.VERSION="1.0.0",exports.default=s;
//# sourceMappingURL=index.js.map