avada-feature-request
v2.0.6
Published
Feature Request component library for React applications
Downloads
2,954
Readme
Avada Feature Request
React component library for feature-request boards in Shopify apps. Real-time updates via SSE, voting, commenting, RBAC, and Shopify Polaris UI.
Installation
npm install avada-feature-request
# or
yarn add avada-feature-requestPeer Dependencies
{
"react": ">=17.0.0",
"react-dom": ">=17.0.0",
"@shopify/polaris": ">=13.0.0"
}Quick Start
Full Feature Request Page
The main component that includes everything: list, create form, detail view, comments, voting, and trending.
import { FeatureRequest } from "avada-feature-request";
function App() {
return (
<FeatureRequest
appId="your-app-id"
activeShop={{
id: "shop-id",
shopId: "shop-id",
email: "[email protected]",
name: "My Shop",
shopOwner: "Owner Name",
}}
isDev={false}
fnAfterSubmit={() => console.log("Submitted!")}
fnAfterLike={() => console.log("Liked!")}
/>
);
}The FeatureRequest component automatically:
- Initializes an SSE connection for realtime updates
- Fetches user roles from the
/check-emailAPI - Manages navigation between 3 pages: Home, Create, Details
Standalone Components
These can be used independently — Provider and SSE subscriptions are already included. No additional wrapping needed.
CreateFeatureReq - Create form
import { CreateFeatureReq } from "avada-feature-request";
<CreateFeatureReq
appId="your-app-id"
activeShop={{ shopId: "shop-id", email: "[email protected]" }}
isDev={false}
isFullPage={true}
/>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| isFullPage | boolean | true | true: full page with back button. false: form input only |
FeatureReqTrending - Trending feature requests
import { FeatureReqTrending } from "avada-feature-request";
<FeatureReqTrending
appId="your-app-id"
activeShop={{ shopId: "shop-id", email: "[email protected]" }}
isDev={false}
isReply={false}
/>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| isReply | boolean | false | true: horizontal slider (for detail page). false: vertical list |
| onNavigate | (path: string) => void | - | Custom navigation handler |
Common Props
All components (FeatureRequest, CreateFeatureReq, FeatureReqTrending) accept the following props:
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| appId | string | Yes | App ID to connect with the backend |
| activeShop | Partial<Shop> | Yes | Current shop information |
| isDev | boolean | Yes | true = staging API, false = production API |
| fnAfterSubmit | () => void | No | Callback after successfully creating a feature request |
| fnAfterLike | () => void | No | Callback after voting/liking |
| translations | DeepPartial<FeatureRequestTranslations> | No | Custom translations (defaults to English) |
activeShop - Shop Information
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| shopId | string | Yes | Shop ID |
| email | string | Yes | Shop owner email (used to check roles) |
| name | string | No | Shop name |
| shopOwner | string | No | Owner name (displayed as author) |
| avatarShop | string | No | Avatar URL |
| domain | string | No | Shop domain (displayed in tooltip) |
Translations (i18n)
Override any text by passing only the keys you want to change:
<FeatureRequest
appId="..."
activeShop={shop}
isDev={false}
translations={{
home: {
pageTitle: "Feature Requests",
submitButton: "Submit Request",
},
create: {
titleLabel: "Title",
descriptionLabel: "Description",
submitButton: "Submit",
},
details: {
writeReply: "Write a comment...",
},
}}
/>Get default translations as a base
import { defaultTranslations } from "avada-feature-request";Translation sections
| Section | Description |
|---------|-------------|
| tabs | Tab filters: All, New feature, Improvement, Bug report, Submitted |
| featureTypes | Feature type options in the create form |
| sort | Sort dropdown: Most recent, Top Voted |
| home | Home page: title, Submit button, end message |
| emptyState | Empty state: title, description |
| create | Create form: labels, placeholders, validation messages |
| details | Detail page: navigation, comment input, buttons |
| card | Feature request card: delete modal, anonymous label, tooltips |
| comments | Comments: reply, block modal, more replies button |
| actions | Like/reply count labels (singular/plural) |
Full translations interface
interface FeatureRequestTranslations {
tabs: {
all: string;
newFeature: string;
improvement: string;
bugReport: string;
submitted: string;
};
featureTypes: { newFeature: string; bugReport: string; improvement: string };
sort: { mostRecent: string; topVoted: string };
home: { pageTitle: string; pageSubtitle: string; submitButton: string; endMessage: string };
emptyState: { title: string; description: string };
create: {
titleLabel: string;
titlePlaceholder: string;
typeLabel: string;
descriptionLabel: string;
descriptionPlaceholder: string;
anonymousLabel: string;
anonymousHelpText: string;
submitButton: string;
backAction: string;
backTitle: string;
titleRequired: string;
descriptionRequired: string;
};
details: {
backAction: string;
backTitle: string;
notFound: string;
commentPlaceholder: string;
cancelButton: string;
replyButton: string;
writeReply: string;
trending: string;
};
card: {
deleteModalTitle: string;
deleteButton: string;
cancelButton: string;
deleteConfirm: string;
anonymous: string;
submittedRequestLabel: string;
domainLabel: string;
};
comments: {
placeholder: string;
cancelButton: string;
replyButton: string;
moreReplies: string;
blockModalTitle: string;
blockButton: string;
blockCancelButton: string;
blockConfirm: string;
};
actions: {
likeSingular: string;
likePlural: string;
replySingular: string;
replyPlural: string;
};
}Exports
Components
import { FeatureRequest } from "avada-feature-request"; // Full page (main)
import { CreateFeatureReq } from "avada-feature-request"; // Standalone create form
import { FeatureReqTrending } from "avada-feature-request"; // Standalone trending
import { NoFeatureRequest } from "avada-feature-request"; // Empty state SVG illustrationTypes
import type {
FeatureRequestProps,
FeatureRequestStage, // "home" | "create" | "details"
FeatureRequestTranslations,
FeatureRequestComment,
FeatureRequestQuery,
ShopSupport,
ActionFeatureReqType,
} from "avada-feature-request";Utilities
import { defaultTranslations } from "avada-feature-request";Event Analytics (Server-side)
A separate sub-path export for logging Shopify events to BigQuery and saving feature stats to Firestore. This is a server-side module (Node.js only).
import { EventLogService, createEventLogService } from "avada-feature-request/event-analytics";Setup
Requires the environment variable GOOGLE_CLOUD_CREDENTIALS_APP_REVIEWS containing your Google Cloud service account JSON.
Usage
import { createEventLogService } from "avada-feature-request/event-analytics";
const eventLogger = createEventLogService({
appId: "your-app-id",
maxRetries: 3, // optional, default: 3
retryDelay: 1000, // optional, default: 1000ms
isDisabled: false, // optional, default: false
});
// Log a single event
await eventLogger.logEvent({
type: "app_installed",
shopifyDomain: "my-shop.myshopify.com",
shopName: "My Shop",
properties: { plan: "premium" },
});
// Log multiple events
await eventLogger.logEvents([
{ type: "app_installed", shopifyDomain: "shop1.myshopify.com" },
{ type: "app_uninstalled", shopifyDomain: "shop2.myshopify.com" },
]);Feature Stats (Firestore)
import { FeatureStatsService, saveFeatureStats } from "avada-feature-request/event-analytics";
// Quick helper
await saveFeatureStats({
appId: "your-app-id",
datasetId: "avada_shopify_reviews",
tableName: "shopify_events",
});
// Or use the class directly with custom config
const statsService = new FeatureStatsService({
collectionName: "featureStats", // optional
projectId: "your-gcp-project", // optional
});
await statsService.save({
appId: "your-app-id",
datasetId: "avada_shopify_reviews",
tableName: "shopify_events",
});Google Cloud Clients
import { createBigQueryClient, createFirestoreClient } from "avada-feature-request/event-analytics";
const bigquery = createBigQueryClient({ projectId: "my-project" }); // optional projectId
const firestore = createFirestoreClient({ projectId: "my-project" });Development
yarn dev # Vite dev server
yarn build # Bundle library + type declarations
yarn test # Run Jest tests
yarn lint # ESLintPublishing
yarn build && npm publish