diff --git a/esoui/ingame/lfg/zo_activityfindertemplate_shared.lua b/esoui/ingame/lfg/zo_activityfindertemplate_shared.lua
new file mode 100644
index 0000000..8b57270
--- /dev/null
+++ b/esoui/ingame/lfg/zo_activityfindertemplate_shared.lua
@@ -0,0 +1,225 @@
+ZO_ACTIVITY_FINDER_REWARD_ENTRY_PADDING = 20
+
+------------------
+--Initialization--
+------------------
+
+ZO_ActivityFinderTemplate_Shared = ZO_Object:Subclass()
+
+function ZO_ActivityFinderTemplate_Shared:New(...)
+    local manager = ZO_Object.New(self)
+    manager:Initialize(...)
+    return manager
+end
+
+function ZO_ActivityFinderTemplate_Shared:Initialize(control, dataManager, categoryData)
+    self.control = control
+    self.dataManager = dataManager
+    self.categoryData = categoryData
+    self.categoryData.activityFinderObject = self
+
+    self:InitializeControls()
+    self:RegisterEvents()
+end
+
+function ZO_ActivityFinderTemplate_Shared:InitializeControls(rewardsTemplate)
+    self:InitializeSingularPanelControls(rewardsTemplate)
+    self:InitializeFragment()
+    self:InitializeFilters()
+end
+
+function ZO_ActivityFinderTemplate_Shared:InitializeFilters()
+    --Meant to be overriden
+end
+
+function ZO_ActivityFinderTemplate_Shared:InitializeFragment()
+    --Meant to be overriden
+end
+
+function ZO_ActivityFinderTemplate_Shared:RegisterEvents()
+    ZO_ACTIVITY_FINDER_ROOT_MANAGER:RegisterCallback("OnUpdateLocationData", function() self:RefreshView() end)
+    ZO_ACTIVITY_FINDER_ROOT_MANAGER:RegisterCallback("OnGroupingToolsStatusUpdate", function() self:OnGroupingToolsStatusUpdate() end)
+    ZO_ACTIVITY_FINDER_ROOT_MANAGER:RegisterCallback("OnHandleLFMPromptResponse", function() self:OnHandleLFMPromptResponse() end)
+    ZO_ACTIVITY_FINDER_ROOT_MANAGER:RegisterCallback("OnLevelUpdate", function() self:RefreshFilters() end)
+    ZO_ACTIVITY_FINDER_ROOT_MANAGER:RegisterCallback("OnCooldownsUpdate", function() self:OnCooldownsUpdate() end)
+end
+
+function ZO_ActivityFinderTemplate_Shared:InitializeSingularPanelControls(rewardsTemplate)
+    local panel = self.control:GetNamedChild("SingularSection")
+
+    self.backgroundTexture = panel:GetNamedChild("Background")
+    self.titleLabel = panel:GetNamedChild("Title")
+    self.descriptionLabel = panel:GetNamedChild("Description")
+    self.groupSizeRangeLabel = panel:GetNamedChild("GroupSizeLabel")
+    
+    local rewardsSection = panel:GetNamedChild("RewardsSection")
+    self.rewardsHeader = rewardsSection:GetNamedChild("Header")
+    local rewardsEntries = rewardsSection:GetNamedChild("Entries")
+    self.rewardEntryPaddingControl = rewardsEntries:GetNamedChild("Padding")
+    local itemRewardControl = rewardsEntries:GetNamedChild("ItemReward")
+    local xpRewardControl = rewardsEntries:GetNamedChild("XPReward")
+
+    ApplyTemplateToControl(itemRewardControl, rewardsTemplate)
+    ApplyTemplateToControl(xpRewardControl, rewardsTemplate)
+    self.itemRewardLabel = itemRewardControl:GetNamedChild("Text")
+    self.itemRewardIcon = itemRewardControl:GetNamedChild("Icon")
+    self.xpRewardLabel = xpRewardControl:GetNamedChild("Text")
+    self.xpRewardIcon = xpRewardControl:GetNamedChild("Icon")
+    self.xpRewardLabel:SetText(zo_strformat(SI_ACTIVITY_FINDER_RANDOM_REWARD_XP_FORMAT, ZO_CommaDelimitNumber(0))) --TODO: Implement XP reward hook
+    self.itemRewardControl = itemRewardControl
+    self.xpRewardControl = xpRewardControl
+
+    self.singularSection = panel
+end
+
+function ZO_ActivityFinderTemplate_Shared:RefreshView()
+    assert(false) --Must override
+end
+
+function ZO_ActivityFinderTemplate_Shared:RefreshFilters()
+    assert(false) --Must override
+end
+
+function ZO_ActivityFinderTemplate_Shared:OnGroupingToolsStatusUpdate()
+    assert(false) --Must override
+end
+
+function ZO_ActivityFinderTemplate_Shared:OnHandleLFMPromptResponse()
+    --Can be overriden
+end
+
+function ZO_ActivityFinderTemplate_Shared:OnCooldownsUpdate()
+    assert(false) --Must override
+end
+
+do
+    local ITEM_REWARD_COLOR_MAP =
+    {
+        [LFG_ITEM_REWARD_TYPE_STANDARD] = GetItemQualityColor(ITEM_QUALITY_MAGIC),
+        [LFG_ITEM_REWARD_TYPE_DAILY] = GetItemQualityColor(ITEM_QUALITY_ARCANE),
+    }
+
+    local DAILY_HEADER = GetString(SI_ACTIVITY_FINDER_RANDOM_DAILY_REWARD_HEADER)
+    local STANDARD_HEADER = GetString(SI_ACTIVITY_FINDER_RANDOM_STANDARD_REWARD_HEADER)
+
+    function ZO_ActivityFinderTemplate_Shared:RefreshRewards(currentSelectionIsRandom, activityType)
+        local hideItemReward = true
+        local hideXPReward = true
+        if currentSelectionIsRandom then
+            local itemRewardType, xpReward = GetLFGActivityRewardData(activityType)
+            if itemRewardType ~= LFG_ITEM_REWARD_TYPE_NONE then
+                self.itemRewardLabel:SetText(GetString("SI_LFGITEMREWARDTYPE", itemRewardType))
+                self.itemRewardLabel:SetColor(ITEM_REWARD_COLOR_MAP[itemRewardType]:UnpackRGBA())
+                hideItemReward = false
+            end
+
+            if xpReward > 0 then
+                self.xpRewardLabel:SetText(zo_strformat(SI_ACTIVITY_FINDER_RANDOM_REWARD_XP_FORMAT, ZO_CommaDelimitNumber(xpReward)))
+                hideXPReward = false
+            end
+        end
+
+        self.itemRewardLabel:SetHidden(hideItemReward)
+        self.itemRewardIcon:SetHidden(hideItemReward)
+        self.rewardEntryPaddingControl:SetWidth(hideItemReward and 0 or ZO_ACTIVITY_FINDER_REWARD_ENTRY_PADDING)
+        self.xpRewardLabel:SetHidden(hideXPReward)
+        self.xpRewardIcon:SetHidden(hideXPReward)
+        if hideItemReward and hideXpReward then
+            self.rewardsHeader:SetHidden(true)
+        else
+            self.rewardsHeader:SetText(IsEligibleForDailyActivityReward() and DAILY_HEADER or STANDARD_HEADER)
+            self.rewardsHeader:SetHidden(false)
+        end
+        self.rewardsHeader:SetHidden(hideItemReward and hideXPReward)
+    end
+end
+
+function ZO_ActivityFinderTemplate_Shared.SetGroupSizeRangeText(labelControl, entryData, groupIconFormat)
+    if entryData.minGroupSize ~= entryData.maxGroupSize then
+        labelControl:SetText(zo_strformat(SI_ACTIVITY_FINDER_GROUP_SIZE_RANGE_FORMAT, entryData.minGroupSize, entryData.maxGroupSize, groupIconFormat))
+    else
+        labelControl:SetText(zo_strformat(SI_ACTIVITY_FINDER_GROUP_SIZE_SIMPLE_FORMAT, entryData.minGroupSize, groupIconFormat))
+    end
+end
+
+function ZO_ActivityFinderTemplate_Shared:GetLFMPromptInfo()
+    local shouldShowLFMPrompt = false
+    local lfmPromptActivityName
+    if CanSendLFMRequest() then
+        local activityType, activityIndex = GetCurrentLFGActivity()
+        local modes = self.dataManager:GetFilterModeData()
+        if ZO_IsElementInNumericallyIndexedTable(modes:GetActivityTypes(), activityType) then
+            shouldShowLFMPrompt = true
+            lfmPromptActivityName = GetLFGOption(activityType, activityIndex)
+        end
+    end
+    return shouldShowLFMPrompt, lfmPromptActivityName
+end
+
+function ZO_ActivityFinderTemplate_Shared:GetLevelLockInfoByActivity(activityType)
+    local isLevelLocked = false
+    local lowestLevelLimit, lowestRankLimit
+
+    local maxLevel = GetMaxLevel()
+
+    local locationData = ZO_ACTIVITY_FINDER_ROOT_MANAGER:GetLocationsData(activityType)
+    for _, location in ipairs(locationData) do
+        if location.levelMin == maxLevel then --This is a veteran activity
+            if not lowestRankLimit or location.veteranRankMin < lowestRankLimit then
+                lowestRankLimit = location.veteranRankMin
+            end
+        else
+            if not lowestLevelLimit or location.levelMin < lowestLevelLimit then
+                lowestLevelLimit = location.levelMin
+            end
+        end
+    end
+    
+    if lowestLevelLimit then
+        if GetUnitLevel("player") < lowestLevelLimit  then
+            isLevelLocked = true
+        end
+    elseif lowestRankLimit then
+        if GetUnitVeteranRank("player") < lowestRankLimit then
+            isLevelLocked = true
+        end
+    end
+
+    return isLevelLocked, lowestLevelLimit, lowestRankLimit
+end
+
+function ZO_ActivityFinderTemplate_Shared:GetLevelLockInfo()
+    local isLevelLocked = true
+    local lowestLevelLimit, lowestRankLimit
+
+    local modes = self.dataManager:GetFilterModeData()
+    for _, activityType in ipairs(modes:GetActivityTypes()) do
+        local locked, level, rank = self:GetLevelLockInfoByActivity(activityType)
+        if level and (not lowestLevelLimit or level < lowestLevelLimit) then
+            lowestLevelLimit = level
+        end
+
+        if rank and (not lowestRankLimit or rank < lowestRankLimit) then
+            lowestRankLimit = rank
+        end
+
+        if not locked then
+            isLevelLocked = false
+        end
+    end
+
+    return isLevelLocked, lowestLevelLimit, lowestRankLimit
+end
+
+function ZO_ActivityFinderTemplate_Shared:GetLevelLockTextByActivity(activityType)
+    local isLocked, levelMin, rankMin = self:GetLevelLockInfoByActivity(activityType)
+    local lockReasonText
+    if isLocked then
+        if levelMin then
+            lockReasonText = zo_strformat(SI_LFG_LOCK_REASON_PLAYER_MIN_LEVEL_REQUIREMENT, levelMin)
+        elseif rankMin then
+            lockReasonText = zo_strformat(SI_LFG_LOCK_REASON_PLAYER_MIN_RANK_REQUIREMENT, rankMin)
+        end
+    end
+    return lockReasonText
+end
\ No newline at end of file